freebsd-dev/sys/compat/ndis/subr_ntoskrnl.c

1973 lines
47 KiB
C
Raw Normal View History

Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
/*
* Copyright (c) 2003
* Bill Paul <wpaul@windriver.com>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Bill Paul.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/ctype.h>
#include <sys/unistd.h>
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
#include <sys/param.h>
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/callout.h>
#include <sys/kdb.h>
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/kthread.h>
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
#include <machine/atomic.h>
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
#include <machine/clock.h>
#include <machine/bus_memio.h>
#include <machine/bus_pio.h>
#include <machine/bus.h>
#include <machine/stdarg.h>
#include <sys/bus.h>
#include <sys/rman.h>
#include <compat/ndis/pe_var.h>
#include <compat/ndis/hal_var.h>
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
#include <compat/ndis/resource_var.h>
#include <compat/ndis/ntoskrnl_var.h>
#include <compat/ndis/ndis_var.h>
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
#define __regparm __attribute__((regparm(3)))
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
#define FUNC void(*)(void)
__stdcall static uint8_t ntoskrnl_unicode_equal(ndis_unicode_string *,
ndis_unicode_string *, uint8_t);
__stdcall static void ntoskrnl_unicode_copy(ndis_unicode_string *,
ndis_unicode_string *);
__stdcall static ndis_status ntoskrnl_unicode_to_ansi(ndis_ansi_string *,
ndis_unicode_string *, uint8_t);
__stdcall static ndis_status ntoskrnl_ansi_to_unicode(ndis_unicode_string *,
ndis_ansi_string *, uint8_t);
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
__stdcall static void *ntoskrnl_iobuildsynchfsdreq(uint32_t, void *,
void *, uint32_t, uint32_t *, void *, void *);
__stdcall static uint32_t ntoskrnl_iofcalldriver(/*void *, void * */ void);
__stdcall static void ntoskrnl_iofcompletereq(/*void *, uint8_t*/ void);
__stdcall static uint32_t ntoskrnl_waitforobjs(uint32_t,
nt_dispatch_header **, uint32_t, uint32_t, uint32_t, uint8_t,
int64_t *, wait_block *);
- Rewrite the timer and event API routines in subr_ndis.c so that they are actually layered on top of the KeTimer API in subr_ntoskrnl.c, just as it is in Windows. This reduces code duplication and more closely imitates the way things are done in Windows. - Modify ndis_encode_parm() to deal with the case where we have a registry key expressed as a hex value ("0x1") which is being read via NdisReadConfiguration() as an int. Previously, we tried to decode things like "0x1" with strtol() using a base of 10, which would always yield 0. This is what was causing problems with the Intel 2200BG Centrino 802.11g driver: the .inf file that comes with it has a key called RadioEnable with a value of 0x1. We incorrectly decoded this value to '0' when it was queried, hence the driver thought we wanted the radio turned off. - In if_ndis.c, most drivers don't accept NDIS_80211_AUTHMODE_AUTO, but NDIS_80211_AUTHMODE_SHARED may not be right in some cases, so for now always use NDIS_80211_AUTHMODE_OPEN. NOTE: There is still one problem with the Intel 2200BG driver: it happens that the kernel stack in Windows is larger than the kernel stack in FreeBSD. The 2200BG driver sometimes eats up more than 2 pages of stack space, which can lead to a double fault panic. For the moment, I got things to work by adding the following to my kernel config file: options KSTACK_PAGES=8 I'm pretty sure 8 is too big; I just picked this value out of a hat as a test, and it happened to work, so I left it. 4 pages might be enough. Unfortunately, I don't think you can dynamically give a thread a larger stack, so I'm not sure how to handle this short of putting a note in the man page about it and dealing with the flood of mail from people who never read man pages.
2004-03-20 23:39:43 +00:00
static void ntoskrnl_wakeup(void *);
static void ntoskrnl_timercall(void *);
static void ntoskrnl_run_dpc(void *);
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
__stdcall static void ntoskrnl_writereg_ushort(uint16_t *, uint16_t);
__stdcall static uint16_t ntoskrnl_readreg_ushort(uint16_t *);
__stdcall static void ntoskrnl_writereg_ulong(uint32_t *, uint32_t);
__stdcall static uint32_t ntoskrnl_readreg_ulong(uint32_t *);
__stdcall static void ntoskrnl_writereg_uchar(uint8_t *, uint8_t);
__stdcall static uint8_t ntoskrnl_readreg_uchar(uint8_t *);
__stdcall static int64_t _allmul(int64_t, int64_t);
__stdcall static int64_t _alldiv(int64_t, int64_t);
__stdcall static int64_t _allrem(int64_t, int64_t);
__regparm static int64_t _allshr(int64_t, uint8_t);
__regparm static int64_t _allshl(int64_t, uint8_t);
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
__stdcall static uint64_t _aullmul(uint64_t, uint64_t);
__stdcall static uint64_t _aulldiv(uint64_t, uint64_t);
__stdcall static uint64_t _aullrem(uint64_t, uint64_t);
__regparm static uint64_t _aullshr(uint64_t, uint8_t);
__regparm static uint64_t _aullshl(uint64_t, uint8_t);
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
__stdcall static void *ntoskrnl_allocfunc(uint32_t, size_t, uint32_t);
__stdcall static void ntoskrnl_freefunc(void *);
static slist_entry *ntoskrnl_pushsl(slist_header *, slist_entry *);
static slist_entry *ntoskrnl_popsl(slist_header *);
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
__stdcall static void ntoskrnl_init_lookaside(paged_lookaside_list *,
lookaside_alloc_func *, lookaside_free_func *,
uint32_t, size_t, uint32_t, uint16_t);
__stdcall static void ntoskrnl_delete_lookaside(paged_lookaside_list *);
__stdcall static void ntoskrnl_init_nplookaside(npaged_lookaside_list *,
lookaside_alloc_func *, lookaside_free_func *,
uint32_t, size_t, uint32_t, uint16_t);
__stdcall static void ntoskrnl_delete_nplookaside(npaged_lookaside_list *);
__stdcall static slist_entry *ntoskrnl_push_slist(/*slist_header *,
subr_ndis.c: - fix ndis_time() so that it returns a time based on the proper epoch (wacky though it may be) - implement NdisInitializeString() and NdisFreeString(), and add stub for NdisMRemoveMiniport() ntoskrnl_var.h: - add missing member to the general_lookaside struct (gl_listentry) subr_ntoskrnl.c: - Fix arguments to the interlocked push/pop routines: 'head' is an slist_header *, not an slist_entry * - Kludge up _fastcall support for the push/pop routines. The _fastcall convention is similar to _stdcall, except the first two available DWORD-sized arguments are passed in %ecx and %edx, respectively. One kludge for this __attribute__ ((regparm(3))), however this isn't entirely right, as it assumes %eax, %ecx and %edx will be used (regparm(2) assumes %eax and %edx). Another kludge is to declare the two fastcall-ed args as local register variables and explicitly assign them to %ecx and %edx, but experimentation showed that gcc would not guard %ecx and %edx against being clobbered. Thus, I came up with a 3rd kludge, which is to use some inline assembly of the form: void *arg1; void *arg2; __asm__("movl %%ecx, %%ecx" : "=c" (arg1)); __asm__("movl %%edx, %%edx" : "=d" (arg2)); This lets gcc know that we're going to reference %ecx and %edx and that it should make an effort not to let it get trampled. This wastes an instruction (movl %reg, %reg is a no-op) but insures proper behavior. It's possible there's a better way to do this though: this is the first time I've used inline assembler in this fashion. The above fixes to ntoskrnl_var.h an subr_ntoskrnl.c make lookaside lists work for the two drivers I have that use them, one of which is an NDIS 5.0 miniport and another which is 5.1.
2003-12-13 07:41:12 +00:00
slist_entry * */ void);
__stdcall static slist_entry *ntoskrnl_pop_slist(/*slist_header * */ void);
__stdcall static slist_entry *ntoskrnl_push_slist_ex(/*slist_header *,
subr_ndis.c: - fix ndis_time() so that it returns a time based on the proper epoch (wacky though it may be) - implement NdisInitializeString() and NdisFreeString(), and add stub for NdisMRemoveMiniport() ntoskrnl_var.h: - add missing member to the general_lookaside struct (gl_listentry) subr_ntoskrnl.c: - Fix arguments to the interlocked push/pop routines: 'head' is an slist_header *, not an slist_entry * - Kludge up _fastcall support for the push/pop routines. The _fastcall convention is similar to _stdcall, except the first two available DWORD-sized arguments are passed in %ecx and %edx, respectively. One kludge for this __attribute__ ((regparm(3))), however this isn't entirely right, as it assumes %eax, %ecx and %edx will be used (regparm(2) assumes %eax and %edx). Another kludge is to declare the two fastcall-ed args as local register variables and explicitly assign them to %ecx and %edx, but experimentation showed that gcc would not guard %ecx and %edx against being clobbered. Thus, I came up with a 3rd kludge, which is to use some inline assembly of the form: void *arg1; void *arg2; __asm__("movl %%ecx, %%ecx" : "=c" (arg1)); __asm__("movl %%edx, %%edx" : "=d" (arg2)); This lets gcc know that we're going to reference %ecx and %edx and that it should make an effort not to let it get trampled. This wastes an instruction (movl %reg, %reg is a no-op) but insures proper behavior. It's possible there's a better way to do this though: this is the first time I've used inline assembler in this fashion. The above fixes to ntoskrnl_var.h an subr_ntoskrnl.c make lookaside lists work for the two drivers I have that use them, one of which is an NDIS 5.0 miniport and another which is 5.1.
2003-12-13 07:41:12 +00:00
slist_entry *,*/ kspin_lock *);
__stdcall static slist_entry *ntoskrnl_pop_slist_ex(/*slist_header *,
subr_ndis.c: - fix ndis_time() so that it returns a time based on the proper epoch (wacky though it may be) - implement NdisInitializeString() and NdisFreeString(), and add stub for NdisMRemoveMiniport() ntoskrnl_var.h: - add missing member to the general_lookaside struct (gl_listentry) subr_ntoskrnl.c: - Fix arguments to the interlocked push/pop routines: 'head' is an slist_header *, not an slist_entry * - Kludge up _fastcall support for the push/pop routines. The _fastcall convention is similar to _stdcall, except the first two available DWORD-sized arguments are passed in %ecx and %edx, respectively. One kludge for this __attribute__ ((regparm(3))), however this isn't entirely right, as it assumes %eax, %ecx and %edx will be used (regparm(2) assumes %eax and %edx). Another kludge is to declare the two fastcall-ed args as local register variables and explicitly assign them to %ecx and %edx, but experimentation showed that gcc would not guard %ecx and %edx against being clobbered. Thus, I came up with a 3rd kludge, which is to use some inline assembly of the form: void *arg1; void *arg2; __asm__("movl %%ecx, %%ecx" : "=c" (arg1)); __asm__("movl %%edx, %%edx" : "=d" (arg2)); This lets gcc know that we're going to reference %ecx and %edx and that it should make an effort not to let it get trampled. This wastes an instruction (movl %reg, %reg is a no-op) but insures proper behavior. It's possible there's a better way to do this though: this is the first time I've used inline assembler in this fashion. The above fixes to ntoskrnl_var.h an subr_ntoskrnl.c make lookaside lists work for the two drivers I have that use them, one of which is an NDIS 5.0 miniport and another which is 5.1.
2003-12-13 07:41:12 +00:00
kspin_lock * */void);
__stdcall static uint32_t
ntoskrnl_interlock_inc(/*volatile uint32_t * */ void);
__stdcall static uint32_t
ntoskrnl_interlock_dec(/*volatile uint32_t * */ void);
__stdcall static void ntoskrnl_interlock_addstat(/*uint64_t,
uint32_t*/ void);
__stdcall static void ntoskrnl_freemdl(ndis_buffer *);
__stdcall static uint32_t ntoskrnl_sizeofmdl(void *, size_t);
__stdcall static void ntoskrnl_build_npaged_mdl(ndis_buffer *);
__stdcall static void *ntoskrnl_mmaplockedpages(ndis_buffer *, uint8_t);
__stdcall static void *ntoskrnl_mmaplockedpages_cache(ndis_buffer *,
uint8_t, uint32_t, void *, uint32_t, uint32_t);
__stdcall static void ntoskrnl_munmaplockedpages(void *, ndis_buffer *);
__stdcall static void ntoskrnl_init_lock(kspin_lock *);
__stdcall static size_t ntoskrnl_memcmp(const void *, const void *, size_t);
__stdcall static void ntoskrnl_init_ansi_string(ndis_ansi_string *, char *);
__stdcall static void ntoskrnl_init_unicode_string(ndis_unicode_string *,
uint16_t *);
__stdcall static void ntoskrnl_free_unicode_string(ndis_unicode_string *);
__stdcall static void ntoskrnl_free_ansi_string(ndis_ansi_string *);
__stdcall static ndis_status ntoskrnl_unicode_to_int(ndis_unicode_string *,
uint32_t, uint32_t *);
static int atoi (const char *);
static long atol (const char *);
static int rand(void);
static void ntoskrnl_time(uint64_t *);
__stdcall static uint8_t ntoskrnl_wdmver(uint8_t, uint8_t);
static void ntoskrnl_thrfunc(void *);
__stdcall static ndis_status ntoskrnl_create_thread(ndis_handle *,
uint32_t, void *, ndis_handle, void *, void *, void *);
__stdcall static ndis_status ntoskrnl_thread_exit(ndis_status);
__stdcall static ndis_status ntoskrnl_devprop(device_object *, uint32_t,
uint32_t, void *, uint32_t *);
__stdcall static void ntoskrnl_init_mutex(kmutant *, uint32_t);
__stdcall static uint32_t ntoskrnl_release_mutex(kmutant *, uint8_t);
__stdcall static uint32_t ntoskrnl_read_mutex(kmutant *);
__stdcall static ndis_status ntoskrnl_objref(ndis_handle, uint32_t, void *,
uint8_t, void **, void **);
__stdcall static void ntoskrnl_objderef(/*void * */ void);
__stdcall static uint32_t ntoskrnl_zwclose(ndis_handle);
static uint32_t ntoskrnl_dbgprint(char *, ...);
__stdcall static void ntoskrnl_debugger(void);
__stdcall static void dummy(void);
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
static struct mtx ntoskrnl_dispatchlock;
static kspin_lock ntoskrnl_global;
static int ntoskrnl_kth = 0;
static struct nt_objref_head ntoskrnl_reflist;
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
int
ntoskrnl_libinit()
{
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_init(&ntoskrnl_dispatchlock,
"ntoskrnl dispatch lock", MTX_NDIS_LOCK, MTX_DEF);
ntoskrnl_init_lock(&ntoskrnl_global);
TAILQ_INIT(&ntoskrnl_reflist);
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
return(0);
}
int
ntoskrnl_libfini()
{
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_destroy(&ntoskrnl_dispatchlock);
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
return(0);
}
__stdcall static uint8_t
ntoskrnl_unicode_equal(str1, str2, caseinsensitive)
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
ndis_unicode_string *str1;
ndis_unicode_string *str2;
uint8_t caseinsensitive;
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
{
int i;
if (str1->nus_len != str2->nus_len)
return(FALSE);
for (i = 0; i < str1->nus_len; i++) {
if (caseinsensitive == TRUE) {
if (toupper((char)(str1->nus_buf[i] & 0xFF)) !=
toupper((char)(str2->nus_buf[i] & 0xFF)))
return(FALSE);
} else {
if (str1->nus_buf[i] != str2->nus_buf[i])
return(FALSE);
}
}
return(TRUE);
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
}
__stdcall static void
ntoskrnl_unicode_copy(dest, src)
ndis_unicode_string *dest;
ndis_unicode_string *src;
{
if (dest->nus_maxlen >= src->nus_len)
dest->nus_len = src->nus_len;
else
dest->nus_len = dest->nus_maxlen;
memcpy(dest->nus_buf, src->nus_buf, dest->nus_len);
return;
}
__stdcall static ndis_status
ntoskrnl_unicode_to_ansi(dest, src, allocate)
ndis_ansi_string *dest;
ndis_unicode_string *src;
uint8_t allocate;
{
char *astr = NULL;
if (dest == NULL || src == NULL)
return(NDIS_STATUS_FAILURE);
if (allocate == TRUE) {
if (ndis_unicode_to_ascii(src->nus_buf, src->nus_len, &astr))
return(NDIS_STATUS_FAILURE);
dest->nas_buf = astr;
dest->nas_len = dest->nas_maxlen = strlen(astr);
} else {
dest->nas_len = src->nus_len / 2; /* XXX */
if (dest->nas_maxlen < dest->nas_len)
dest->nas_len = dest->nas_maxlen;
ndis_unicode_to_ascii(src->nus_buf, dest->nas_len * 2,
&dest->nas_buf);
}
return (NDIS_STATUS_SUCCESS);
}
__stdcall static ndis_status
ntoskrnl_ansi_to_unicode(dest, src, allocate)
ndis_unicode_string *dest;
ndis_ansi_string *src;
uint8_t allocate;
{
uint16_t *ustr = NULL;
if (dest == NULL || src == NULL)
return(NDIS_STATUS_FAILURE);
if (allocate == TRUE) {
if (ndis_ascii_to_unicode(src->nas_buf, &ustr))
return(NDIS_STATUS_FAILURE);
dest->nus_buf = ustr;
dest->nus_len = dest->nus_maxlen = strlen(src->nas_buf) * 2;
} else {
dest->nus_len = src->nas_len * 2; /* XXX */
if (dest->nus_maxlen < dest->nus_len)
dest->nus_len = dest->nus_maxlen;
ndis_ascii_to_unicode(src->nas_buf, &dest->nus_buf);
}
return (NDIS_STATUS_SUCCESS);
}
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
__stdcall static void *
ntoskrnl_iobuildsynchfsdreq(func, dobj, buf, len, off, event, status)
uint32_t func;
void *dobj;
void *buf;
uint32_t len;
uint32_t *off;
void *event;
void *status;
{
return(NULL);
}
__stdcall static uint32_t
ntoskrnl_iofcalldriver(/*dobj, irp*/)
{
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
void *dobj;
void *irp;
__asm__ __volatile__ ("" : "=c" (dobj), "=d" (irp));
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
return(0);
}
__stdcall static void
ntoskrnl_iofcompletereq(/*irp, prioboost*/)
{
void *irp;
uint8_t prioboost;
__asm__ __volatile__ ("" : "=c" (irp), "=d" (prioboost));
return;
}
- Rewrite the timer and event API routines in subr_ndis.c so that they are actually layered on top of the KeTimer API in subr_ntoskrnl.c, just as it is in Windows. This reduces code duplication and more closely imitates the way things are done in Windows. - Modify ndis_encode_parm() to deal with the case where we have a registry key expressed as a hex value ("0x1") which is being read via NdisReadConfiguration() as an int. Previously, we tried to decode things like "0x1" with strtol() using a base of 10, which would always yield 0. This is what was causing problems with the Intel 2200BG Centrino 802.11g driver: the .inf file that comes with it has a key called RadioEnable with a value of 0x1. We incorrectly decoded this value to '0' when it was queried, hence the driver thought we wanted the radio turned off. - In if_ndis.c, most drivers don't accept NDIS_80211_AUTHMODE_AUTO, but NDIS_80211_AUTHMODE_SHARED may not be right in some cases, so for now always use NDIS_80211_AUTHMODE_OPEN. NOTE: There is still one problem with the Intel 2200BG driver: it happens that the kernel stack in Windows is larger than the kernel stack in FreeBSD. The 2200BG driver sometimes eats up more than 2 pages of stack space, which can lead to a double fault panic. For the moment, I got things to work by adding the following to my kernel config file: options KSTACK_PAGES=8 I'm pretty sure 8 is too big; I just picked this value out of a hat as a test, and it happened to work, so I left it. 4 pages might be enough. Unfortunately, I don't think you can dynamically give a thread a larger stack, so I'm not sure how to handle this short of putting a note in the man page about it and dealing with the flood of mail from people who never read man pages.
2004-03-20 23:39:43 +00:00
static void
ntoskrnl_wakeup(arg)
void *arg;
{
nt_dispatch_header *obj;
wait_block *w;
list_entry *e;
struct thread *td;
obj = arg;
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_lock(&ntoskrnl_dispatchlock);
obj->dh_sigstate = TRUE;
e = obj->dh_waitlisthead.nle_flink;
while (e != &obj->dh_waitlisthead) {
w = (wait_block *)e;
td = w->wb_kthread;
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
ndis_thresume(td->td_proc);
/*
* For synchronization objects, only wake up
* the first waiter.
*/
if (obj->dh_type == EVENT_TYPE_SYNC)
break;
e = e->nle_flink;
}
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_unlock(&ntoskrnl_dispatchlock);
return;
}
static void
ntoskrnl_time(tval)
uint64_t *tval;
{
struct timespec ts;
nanotime(&ts);
*tval = (uint64_t)ts.tv_nsec / 100 + (uint64_t)ts.tv_sec * 10000000 +
11644473600;
return;
}
/*
* KeWaitForSingleObject() is a tricky beast, because it can be used
* with several different object types: semaphores, timers, events,
* mutexes and threads. Semaphores don't appear very often, but the
* other object types are quite common. KeWaitForSingleObject() is
* what's normally used to acquire a mutex, and it can be used to
* wait for a thread termination.
*
* The Windows NDIS API is implemented in terms of Windows kernel
* primitives, and some of the object manipulation is duplicated in
* NDIS. For example, NDIS has timers and events, which are actually
* Windows kevents and ktimers. Now, you're supposed to only use the
* NDIS variants of these objects within the confines of the NDIS API,
* but there are some naughty developers out there who will use
* KeWaitForSingleObject() on NDIS timer and event objects, so we
* have to support that as well. Conseqently, our NDIS timer and event
* code has to be closely tied into our ntoskrnl timer and event code,
* just as it is in Windows.
*
* KeWaitForSingleObject() may do different things for different kinds
* of objects:
*
* - For events, we check if the event has been signalled. If the
* event is already in the signalled state, we just return immediately,
* otherwise we wait for it to be set to the signalled state by someone
* else calling KeSetEvent(). Events can be either synchronization or
* notification events.
*
* - For timers, if the timer has already fired and the timer is in
* the signalled state, we just return, otherwise we wait on the
* timer. Unlike an event, timers get signalled automatically when
* they expire rather than someone having to trip them manually.
* Timers initialized with KeInitializeTimer() are always notification
* events: KeInitializeTimerEx() lets you initialize a timer as
* either a notification or synchronization event.
*
* - For mutexes, we try to acquire the mutex and if we can't, we wait
* on the mutex until it's available and then grab it. When a mutex is
* released, it enters the signaled state, which wakes up one of the
* threads waiting to acquire it. Mutexes are always synchronization
* events.
*
* - For threads, the only thing we do is wait until the thread object
* enters a signalled state, which occurs when the thread terminates.
* Threads are always notification events.
*
* A notification event wakes up all threads waiting on an object. A
* synchronization event wakes up just one. Also, a synchronization event
* is auto-clearing, which means we automatically set the event back to
* the non-signalled state once the wakeup is done.
*/
- Rewrite the timer and event API routines in subr_ndis.c so that they are actually layered on top of the KeTimer API in subr_ntoskrnl.c, just as it is in Windows. This reduces code duplication and more closely imitates the way things are done in Windows. - Modify ndis_encode_parm() to deal with the case where we have a registry key expressed as a hex value ("0x1") which is being read via NdisReadConfiguration() as an int. Previously, we tried to decode things like "0x1" with strtol() using a base of 10, which would always yield 0. This is what was causing problems with the Intel 2200BG Centrino 802.11g driver: the .inf file that comes with it has a key called RadioEnable with a value of 0x1. We incorrectly decoded this value to '0' when it was queried, hence the driver thought we wanted the radio turned off. - In if_ndis.c, most drivers don't accept NDIS_80211_AUTHMODE_AUTO, but NDIS_80211_AUTHMODE_SHARED may not be right in some cases, so for now always use NDIS_80211_AUTHMODE_OPEN. NOTE: There is still one problem with the Intel 2200BG driver: it happens that the kernel stack in Windows is larger than the kernel stack in FreeBSD. The 2200BG driver sometimes eats up more than 2 pages of stack space, which can lead to a double fault panic. For the moment, I got things to work by adding the following to my kernel config file: options KSTACK_PAGES=8 I'm pretty sure 8 is too big; I just picked this value out of a hat as a test, and it happened to work, so I left it. 4 pages might be enough. Unfortunately, I don't think you can dynamically give a thread a larger stack, so I'm not sure how to handle this short of putting a note in the man page about it and dealing with the flood of mail from people who never read man pages.
2004-03-20 23:39:43 +00:00
__stdcall uint32_t
Fix several issues related to the KeInitializeTimer() etc... API stuff that I added recently: - When a periodic timer fires, it's automatically re-armed. We must make sure to re-arm the timer _before_ invoking any caller-supplied defered procedure call: the DPC may choose to call KeCancelTimer(), and re-arming the timer after the DPC un-does the effect of the cancel. - Fix similar issue with periodic timers in subr_ndis.c. - When calling KeSetTimer() or KeSetTimerEx(), if the timer is already pending, untimeout() it first before timeout()ing it again. - The old Atheros driver for the 5211 seems to use KeSetTimerEx() incorrectly, or at the very least in a very strange way that doesn't quite follow the Microsoft documentation. In one case, it calls KeSetTimerEx() with a duetime of 0 and a period of 5000. The Microsoft documentation says that negative duetime values are relative to the current time and positive values are absolute. But it doesn't say what's supposed to happen with positive values that less than the current time, i.e. absolute values that are in the past. Lacking any further information, I have decided that timers with positive duetimes that are in the past should fire right away (or in our case, after only 1 tick). This also takes care of the other strange usage in the Atheros driver, where the duetime is specified as 500000 and the period is 50. I think someone may have meant to use -500000 and misinterpreted the documentation. - Also modified KeWaitForSingleObject() and KeWaitForMultipleObjects() to make the same duetime adjustment, since they have the same rules regarding timeout values. - Cosmetic: change name of 'timeout' variable in KeWaitForSingleObject() and KeWaitForMultipleObjects() to 'duetime' to avoid senseless (though harmless) overlap with timeout() function name. With these fixes, I can get the 5211 card to associate properly with my adhoc net using driver AR5211.SYS version 2.4.1.6.
2004-03-10 07:43:11 +00:00
ntoskrnl_waitforobj(obj, reason, mode, alertable, duetime)
nt_dispatch_header *obj;
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
uint32_t reason;
uint32_t mode;
uint8_t alertable;
Fix several issues related to the KeInitializeTimer() etc... API stuff that I added recently: - When a periodic timer fires, it's automatically re-armed. We must make sure to re-arm the timer _before_ invoking any caller-supplied defered procedure call: the DPC may choose to call KeCancelTimer(), and re-arming the timer after the DPC un-does the effect of the cancel. - Fix similar issue with periodic timers in subr_ndis.c. - When calling KeSetTimer() or KeSetTimerEx(), if the timer is already pending, untimeout() it first before timeout()ing it again. - The old Atheros driver for the 5211 seems to use KeSetTimerEx() incorrectly, or at the very least in a very strange way that doesn't quite follow the Microsoft documentation. In one case, it calls KeSetTimerEx() with a duetime of 0 and a period of 5000. The Microsoft documentation says that negative duetime values are relative to the current time and positive values are absolute. But it doesn't say what's supposed to happen with positive values that less than the current time, i.e. absolute values that are in the past. Lacking any further information, I have decided that timers with positive duetimes that are in the past should fire right away (or in our case, after only 1 tick). This also takes care of the other strange usage in the Atheros driver, where the duetime is specified as 500000 and the period is 50. I think someone may have meant to use -500000 and misinterpreted the documentation. - Also modified KeWaitForSingleObject() and KeWaitForMultipleObjects() to make the same duetime adjustment, since they have the same rules regarding timeout values. - Cosmetic: change name of 'timeout' variable in KeWaitForSingleObject() and KeWaitForMultipleObjects() to 'duetime' to avoid senseless (though harmless) overlap with timeout() function name. With these fixes, I can get the 5211 card to associate properly with my adhoc net using driver AR5211.SYS version 2.4.1.6.
2004-03-10 07:43:11 +00:00
int64_t *duetime;
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
{
struct thread *td = curthread;
kmutant *km;
wait_block w;
struct timeval tv;
int error = 0;
uint64_t curtime;
if (obj == NULL)
return(STATUS_INVALID_PARAMETER);
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_lock(&ntoskrnl_dispatchlock);
/*
* See if the object is a mutex. If so, and we already own
* it, then just increment the acquisition count and return.
*
* For any other kind of object, see if it's already in the
* signalled state, and if it is, just return. If the object
* is marked as a synchronization event, reset the state to
* unsignalled.
*/
if (obj->dh_size == OTYPE_MUTEX) {
km = (kmutant *)obj;
if (km->km_ownerthread == NULL ||
km->km_ownerthread == curthread->td_proc) {
obj->dh_sigstate = FALSE;
km->km_acquirecnt++;
km->km_ownerthread = curthread->td_proc;
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_unlock(&ntoskrnl_dispatchlock);
return (STATUS_SUCCESS);
}
} else if (obj->dh_sigstate == TRUE) {
if (obj->dh_type == EVENT_TYPE_SYNC)
obj->dh_sigstate = FALSE;
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_unlock(&ntoskrnl_dispatchlock);
return (STATUS_SUCCESS);
}
w.wb_object = obj;
w.wb_kthread = td;
INSERT_LIST_TAIL((&obj->dh_waitlisthead), (&w.wb_waitlist));
/*
* The timeout value is specified in 100 nanosecond units
* and can be a positive or negative number. If it's positive,
Fix several issues related to the KeInitializeTimer() etc... API stuff that I added recently: - When a periodic timer fires, it's automatically re-armed. We must make sure to re-arm the timer _before_ invoking any caller-supplied defered procedure call: the DPC may choose to call KeCancelTimer(), and re-arming the timer after the DPC un-does the effect of the cancel. - Fix similar issue with periodic timers in subr_ndis.c. - When calling KeSetTimer() or KeSetTimerEx(), if the timer is already pending, untimeout() it first before timeout()ing it again. - The old Atheros driver for the 5211 seems to use KeSetTimerEx() incorrectly, or at the very least in a very strange way that doesn't quite follow the Microsoft documentation. In one case, it calls KeSetTimerEx() with a duetime of 0 and a period of 5000. The Microsoft documentation says that negative duetime values are relative to the current time and positive values are absolute. But it doesn't say what's supposed to happen with positive values that less than the current time, i.e. absolute values that are in the past. Lacking any further information, I have decided that timers with positive duetimes that are in the past should fire right away (or in our case, after only 1 tick). This also takes care of the other strange usage in the Atheros driver, where the duetime is specified as 500000 and the period is 50. I think someone may have meant to use -500000 and misinterpreted the documentation. - Also modified KeWaitForSingleObject() and KeWaitForMultipleObjects() to make the same duetime adjustment, since they have the same rules regarding timeout values. - Cosmetic: change name of 'timeout' variable in KeWaitForSingleObject() and KeWaitForMultipleObjects() to 'duetime' to avoid senseless (though harmless) overlap with timeout() function name. With these fixes, I can get the 5211 card to associate properly with my adhoc net using driver AR5211.SYS version 2.4.1.6.
2004-03-10 07:43:11 +00:00
* then the duetime is absolute, and we need to convert it
* to an absolute offset relative to now in order to use it.
Fix several issues related to the KeInitializeTimer() etc... API stuff that I added recently: - When a periodic timer fires, it's automatically re-armed. We must make sure to re-arm the timer _before_ invoking any caller-supplied defered procedure call: the DPC may choose to call KeCancelTimer(), and re-arming the timer after the DPC un-does the effect of the cancel. - Fix similar issue with periodic timers in subr_ndis.c. - When calling KeSetTimer() or KeSetTimerEx(), if the timer is already pending, untimeout() it first before timeout()ing it again. - The old Atheros driver for the 5211 seems to use KeSetTimerEx() incorrectly, or at the very least in a very strange way that doesn't quite follow the Microsoft documentation. In one case, it calls KeSetTimerEx() with a duetime of 0 and a period of 5000. The Microsoft documentation says that negative duetime values are relative to the current time and positive values are absolute. But it doesn't say what's supposed to happen with positive values that less than the current time, i.e. absolute values that are in the past. Lacking any further information, I have decided that timers with positive duetimes that are in the past should fire right away (or in our case, after only 1 tick). This also takes care of the other strange usage in the Atheros driver, where the duetime is specified as 500000 and the period is 50. I think someone may have meant to use -500000 and misinterpreted the documentation. - Also modified KeWaitForSingleObject() and KeWaitForMultipleObjects() to make the same duetime adjustment, since they have the same rules regarding timeout values. - Cosmetic: change name of 'timeout' variable in KeWaitForSingleObject() and KeWaitForMultipleObjects() to 'duetime' to avoid senseless (though harmless) overlap with timeout() function name. With these fixes, I can get the 5211 card to associate properly with my adhoc net using driver AR5211.SYS version 2.4.1.6.
2004-03-10 07:43:11 +00:00
* If it's negative, then the duetime is relative and we
* just have to convert the units.
*/
Fix several issues related to the KeInitializeTimer() etc... API stuff that I added recently: - When a periodic timer fires, it's automatically re-armed. We must make sure to re-arm the timer _before_ invoking any caller-supplied defered procedure call: the DPC may choose to call KeCancelTimer(), and re-arming the timer after the DPC un-does the effect of the cancel. - Fix similar issue with periodic timers in subr_ndis.c. - When calling KeSetTimer() or KeSetTimerEx(), if the timer is already pending, untimeout() it first before timeout()ing it again. - The old Atheros driver for the 5211 seems to use KeSetTimerEx() incorrectly, or at the very least in a very strange way that doesn't quite follow the Microsoft documentation. In one case, it calls KeSetTimerEx() with a duetime of 0 and a period of 5000. The Microsoft documentation says that negative duetime values are relative to the current time and positive values are absolute. But it doesn't say what's supposed to happen with positive values that less than the current time, i.e. absolute values that are in the past. Lacking any further information, I have decided that timers with positive duetimes that are in the past should fire right away (or in our case, after only 1 tick). This also takes care of the other strange usage in the Atheros driver, where the duetime is specified as 500000 and the period is 50. I think someone may have meant to use -500000 and misinterpreted the documentation. - Also modified KeWaitForSingleObject() and KeWaitForMultipleObjects() to make the same duetime adjustment, since they have the same rules regarding timeout values. - Cosmetic: change name of 'timeout' variable in KeWaitForSingleObject() and KeWaitForMultipleObjects() to 'duetime' to avoid senseless (though harmless) overlap with timeout() function name. With these fixes, I can get the 5211 card to associate properly with my adhoc net using driver AR5211.SYS version 2.4.1.6.
2004-03-10 07:43:11 +00:00
if (duetime != NULL) {
if (*duetime < 0) {
tv.tv_sec = - (*duetime) / 10000000;
tv.tv_usec = (- (*duetime) / 10) -
(tv.tv_sec * 1000000);
} else {
ntoskrnl_time(&curtime);
Fix several issues related to the KeInitializeTimer() etc... API stuff that I added recently: - When a periodic timer fires, it's automatically re-armed. We must make sure to re-arm the timer _before_ invoking any caller-supplied defered procedure call: the DPC may choose to call KeCancelTimer(), and re-arming the timer after the DPC un-does the effect of the cancel. - Fix similar issue with periodic timers in subr_ndis.c. - When calling KeSetTimer() or KeSetTimerEx(), if the timer is already pending, untimeout() it first before timeout()ing it again. - The old Atheros driver for the 5211 seems to use KeSetTimerEx() incorrectly, or at the very least in a very strange way that doesn't quite follow the Microsoft documentation. In one case, it calls KeSetTimerEx() with a duetime of 0 and a period of 5000. The Microsoft documentation says that negative duetime values are relative to the current time and positive values are absolute. But it doesn't say what's supposed to happen with positive values that less than the current time, i.e. absolute values that are in the past. Lacking any further information, I have decided that timers with positive duetimes that are in the past should fire right away (or in our case, after only 1 tick). This also takes care of the other strange usage in the Atheros driver, where the duetime is specified as 500000 and the period is 50. I think someone may have meant to use -500000 and misinterpreted the documentation. - Also modified KeWaitForSingleObject() and KeWaitForMultipleObjects() to make the same duetime adjustment, since they have the same rules regarding timeout values. - Cosmetic: change name of 'timeout' variable in KeWaitForSingleObject() and KeWaitForMultipleObjects() to 'duetime' to avoid senseless (though harmless) overlap with timeout() function name. With these fixes, I can get the 5211 card to associate properly with my adhoc net using driver AR5211.SYS version 2.4.1.6.
2004-03-10 07:43:11 +00:00
if (*duetime < curtime)
tv.tv_sec = tv.tv_usec = 0;
else {
tv.tv_sec = ((*duetime) - curtime) / 10000000;
tv.tv_usec = ((*duetime) - curtime) / 10 -
(tv.tv_sec * 1000000);
}
}
}
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_unlock(&ntoskrnl_dispatchlock);
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
error = ndis_thsuspend(td->td_proc,
duetime == NULL ? 0 : tvtohz(&tv));
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_lock(&ntoskrnl_dispatchlock);
/* We timed out. Leave the object alone and return status. */
if (error == EWOULDBLOCK) {
REMOVE_LIST_ENTRY((&w.wb_waitlist));
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_unlock(&ntoskrnl_dispatchlock);
return(STATUS_TIMEOUT);
}
/*
* Mutexes are always synchronization objects, which means
* if several threads are waiting to acquire it, only one will
* be woken up. If that one is us, and the mutex is up for grabs,
* grab it.
*/
if (obj->dh_size == OTYPE_MUTEX) {
km = (kmutant *)obj;
if (km->km_ownerthread == NULL) {
km->km_ownerthread = curthread->td_proc;
km->km_acquirecnt++;
}
}
if (obj->dh_type == EVENT_TYPE_SYNC)
obj->dh_sigstate = FALSE;
REMOVE_LIST_ENTRY((&w.wb_waitlist));
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_unlock(&ntoskrnl_dispatchlock);
return(STATUS_SUCCESS);
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
}
__stdcall static uint32_t
ntoskrnl_waitforobjs(cnt, obj, wtype, reason, mode,
Fix several issues related to the KeInitializeTimer() etc... API stuff that I added recently: - When a periodic timer fires, it's automatically re-armed. We must make sure to re-arm the timer _before_ invoking any caller-supplied defered procedure call: the DPC may choose to call KeCancelTimer(), and re-arming the timer after the DPC un-does the effect of the cancel. - Fix similar issue with periodic timers in subr_ndis.c. - When calling KeSetTimer() or KeSetTimerEx(), if the timer is already pending, untimeout() it first before timeout()ing it again. - The old Atheros driver for the 5211 seems to use KeSetTimerEx() incorrectly, or at the very least in a very strange way that doesn't quite follow the Microsoft documentation. In one case, it calls KeSetTimerEx() with a duetime of 0 and a period of 5000. The Microsoft documentation says that negative duetime values are relative to the current time and positive values are absolute. But it doesn't say what's supposed to happen with positive values that less than the current time, i.e. absolute values that are in the past. Lacking any further information, I have decided that timers with positive duetimes that are in the past should fire right away (or in our case, after only 1 tick). This also takes care of the other strange usage in the Atheros driver, where the duetime is specified as 500000 and the period is 50. I think someone may have meant to use -500000 and misinterpreted the documentation. - Also modified KeWaitForSingleObject() and KeWaitForMultipleObjects() to make the same duetime adjustment, since they have the same rules regarding timeout values. - Cosmetic: change name of 'timeout' variable in KeWaitForSingleObject() and KeWaitForMultipleObjects() to 'duetime' to avoid senseless (though harmless) overlap with timeout() function name. With these fixes, I can get the 5211 card to associate properly with my adhoc net using driver AR5211.SYS version 2.4.1.6.
2004-03-10 07:43:11 +00:00
alertable, duetime, wb_array)
uint32_t cnt;
nt_dispatch_header *obj[];
uint32_t wtype;
uint32_t reason;
uint32_t mode;
uint8_t alertable;
Fix several issues related to the KeInitializeTimer() etc... API stuff that I added recently: - When a periodic timer fires, it's automatically re-armed. We must make sure to re-arm the timer _before_ invoking any caller-supplied defered procedure call: the DPC may choose to call KeCancelTimer(), and re-arming the timer after the DPC un-does the effect of the cancel. - Fix similar issue with periodic timers in subr_ndis.c. - When calling KeSetTimer() or KeSetTimerEx(), if the timer is already pending, untimeout() it first before timeout()ing it again. - The old Atheros driver for the 5211 seems to use KeSetTimerEx() incorrectly, or at the very least in a very strange way that doesn't quite follow the Microsoft documentation. In one case, it calls KeSetTimerEx() with a duetime of 0 and a period of 5000. The Microsoft documentation says that negative duetime values are relative to the current time and positive values are absolute. But it doesn't say what's supposed to happen with positive values that less than the current time, i.e. absolute values that are in the past. Lacking any further information, I have decided that timers with positive duetimes that are in the past should fire right away (or in our case, after only 1 tick). This also takes care of the other strange usage in the Atheros driver, where the duetime is specified as 500000 and the period is 50. I think someone may have meant to use -500000 and misinterpreted the documentation. - Also modified KeWaitForSingleObject() and KeWaitForMultipleObjects() to make the same duetime adjustment, since they have the same rules regarding timeout values. - Cosmetic: change name of 'timeout' variable in KeWaitForSingleObject() and KeWaitForMultipleObjects() to 'duetime' to avoid senseless (though harmless) overlap with timeout() function name. With these fixes, I can get the 5211 card to associate properly with my adhoc net using driver AR5211.SYS version 2.4.1.6.
2004-03-10 07:43:11 +00:00
int64_t *duetime;
wait_block *wb_array;
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
{
struct thread *td = curthread;
kmutant *km;
wait_block _wb_array[THREAD_WAIT_OBJECTS];
wait_block *w;
struct timeval tv;
int i, wcnt = 0, widx = 0, error = 0;
uint64_t curtime;
struct timespec t1, t2;
if (cnt > MAX_WAIT_OBJECTS)
return(STATUS_INVALID_PARAMETER);
if (cnt > THREAD_WAIT_OBJECTS && wb_array == NULL)
return(STATUS_INVALID_PARAMETER);
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_lock(&ntoskrnl_dispatchlock);
if (wb_array == NULL)
w = &_wb_array[0];
else
w = wb_array;
/* First pass: see if we can satisfy any waits immediately. */
for (i = 0; i < cnt; i++) {
if (obj[i]->dh_size == OTYPE_MUTEX) {
km = (kmutant *)obj[i];
if (km->km_ownerthread == NULL ||
km->km_ownerthread == curthread->td_proc) {
obj[i]->dh_sigstate = FALSE;
km->km_acquirecnt++;
km->km_ownerthread = curthread->td_proc;
if (wtype == WAITTYPE_ANY) {
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_unlock(&ntoskrnl_dispatchlock);
return (STATUS_WAIT_0 + i);
}
}
} else if (obj[i]->dh_sigstate == TRUE) {
if (obj[i]->dh_type == EVENT_TYPE_SYNC)
obj[i]->dh_sigstate = FALSE;
if (wtype == WAITTYPE_ANY) {
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_unlock(&ntoskrnl_dispatchlock);
return (STATUS_WAIT_0 + i);
}
}
}
/*
* Second pass: set up wait for anything we can't
* satisfy immediately.
*/
for (i = 0; i < cnt; i++) {
if (obj[i]->dh_sigstate == TRUE)
continue;
INSERT_LIST_TAIL((&obj[i]->dh_waitlisthead),
(&w[i].wb_waitlist));
w[i].wb_kthread = td;
w[i].wb_object = obj[i];
wcnt++;
}
Fix several issues related to the KeInitializeTimer() etc... API stuff that I added recently: - When a periodic timer fires, it's automatically re-armed. We must make sure to re-arm the timer _before_ invoking any caller-supplied defered procedure call: the DPC may choose to call KeCancelTimer(), and re-arming the timer after the DPC un-does the effect of the cancel. - Fix similar issue with periodic timers in subr_ndis.c. - When calling KeSetTimer() or KeSetTimerEx(), if the timer is already pending, untimeout() it first before timeout()ing it again. - The old Atheros driver for the 5211 seems to use KeSetTimerEx() incorrectly, or at the very least in a very strange way that doesn't quite follow the Microsoft documentation. In one case, it calls KeSetTimerEx() with a duetime of 0 and a period of 5000. The Microsoft documentation says that negative duetime values are relative to the current time and positive values are absolute. But it doesn't say what's supposed to happen with positive values that less than the current time, i.e. absolute values that are in the past. Lacking any further information, I have decided that timers with positive duetimes that are in the past should fire right away (or in our case, after only 1 tick). This also takes care of the other strange usage in the Atheros driver, where the duetime is specified as 500000 and the period is 50. I think someone may have meant to use -500000 and misinterpreted the documentation. - Also modified KeWaitForSingleObject() and KeWaitForMultipleObjects() to make the same duetime adjustment, since they have the same rules regarding timeout values. - Cosmetic: change name of 'timeout' variable in KeWaitForSingleObject() and KeWaitForMultipleObjects() to 'duetime' to avoid senseless (though harmless) overlap with timeout() function name. With these fixes, I can get the 5211 card to associate properly with my adhoc net using driver AR5211.SYS version 2.4.1.6.
2004-03-10 07:43:11 +00:00
if (duetime != NULL) {
if (*duetime < 0) {
tv.tv_sec = - (*duetime) / 10000000;
tv.tv_usec = (- (*duetime) / 10) -
(tv.tv_sec * 1000000);
} else {
ntoskrnl_time(&curtime);
Fix several issues related to the KeInitializeTimer() etc... API stuff that I added recently: - When a periodic timer fires, it's automatically re-armed. We must make sure to re-arm the timer _before_ invoking any caller-supplied defered procedure call: the DPC may choose to call KeCancelTimer(), and re-arming the timer after the DPC un-does the effect of the cancel. - Fix similar issue with periodic timers in subr_ndis.c. - When calling KeSetTimer() or KeSetTimerEx(), if the timer is already pending, untimeout() it first before timeout()ing it again. - The old Atheros driver for the 5211 seems to use KeSetTimerEx() incorrectly, or at the very least in a very strange way that doesn't quite follow the Microsoft documentation. In one case, it calls KeSetTimerEx() with a duetime of 0 and a period of 5000. The Microsoft documentation says that negative duetime values are relative to the current time and positive values are absolute. But it doesn't say what's supposed to happen with positive values that less than the current time, i.e. absolute values that are in the past. Lacking any further information, I have decided that timers with positive duetimes that are in the past should fire right away (or in our case, after only 1 tick). This also takes care of the other strange usage in the Atheros driver, where the duetime is specified as 500000 and the period is 50. I think someone may have meant to use -500000 and misinterpreted the documentation. - Also modified KeWaitForSingleObject() and KeWaitForMultipleObjects() to make the same duetime adjustment, since they have the same rules regarding timeout values. - Cosmetic: change name of 'timeout' variable in KeWaitForSingleObject() and KeWaitForMultipleObjects() to 'duetime' to avoid senseless (though harmless) overlap with timeout() function name. With these fixes, I can get the 5211 card to associate properly with my adhoc net using driver AR5211.SYS version 2.4.1.6.
2004-03-10 07:43:11 +00:00
if (*duetime < curtime)
tv.tv_sec = tv.tv_usec = 0;
else {
tv.tv_sec = ((*duetime) - curtime) / 10000000;
tv.tv_usec = ((*duetime) - curtime) / 10 -
(tv.tv_sec * 1000000);
}
}
}
while (wcnt) {
nanotime(&t1);
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_unlock(&ntoskrnl_dispatchlock);
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
error = ndis_thsuspend(td->td_proc,
duetime == NULL ? 0 : tvtohz(&tv));
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_lock(&ntoskrnl_dispatchlock);
nanotime(&t2);
for (i = 0; i < cnt; i++) {
if (obj[i]->dh_size == OTYPE_MUTEX) {
km = (kmutant *)obj;
if (km->km_ownerthread == NULL) {
km->km_ownerthread =
curthread->td_proc;
km->km_acquirecnt++;
}
}
if (obj[i]->dh_sigstate == TRUE) {
widx = i;
if (obj[i]->dh_type == EVENT_TYPE_SYNC)
obj[i]->dh_sigstate = FALSE;
REMOVE_LIST_ENTRY((&w[i].wb_waitlist));
wcnt--;
}
}
if (error || wtype == WAITTYPE_ANY)
break;
Fix several issues related to the KeInitializeTimer() etc... API stuff that I added recently: - When a periodic timer fires, it's automatically re-armed. We must make sure to re-arm the timer _before_ invoking any caller-supplied defered procedure call: the DPC may choose to call KeCancelTimer(), and re-arming the timer after the DPC un-does the effect of the cancel. - Fix similar issue with periodic timers in subr_ndis.c. - When calling KeSetTimer() or KeSetTimerEx(), if the timer is already pending, untimeout() it first before timeout()ing it again. - The old Atheros driver for the 5211 seems to use KeSetTimerEx() incorrectly, or at the very least in a very strange way that doesn't quite follow the Microsoft documentation. In one case, it calls KeSetTimerEx() with a duetime of 0 and a period of 5000. The Microsoft documentation says that negative duetime values are relative to the current time and positive values are absolute. But it doesn't say what's supposed to happen with positive values that less than the current time, i.e. absolute values that are in the past. Lacking any further information, I have decided that timers with positive duetimes that are in the past should fire right away (or in our case, after only 1 tick). This also takes care of the other strange usage in the Atheros driver, where the duetime is specified as 500000 and the period is 50. I think someone may have meant to use -500000 and misinterpreted the documentation. - Also modified KeWaitForSingleObject() and KeWaitForMultipleObjects() to make the same duetime adjustment, since they have the same rules regarding timeout values. - Cosmetic: change name of 'timeout' variable in KeWaitForSingleObject() and KeWaitForMultipleObjects() to 'duetime' to avoid senseless (though harmless) overlap with timeout() function name. With these fixes, I can get the 5211 card to associate properly with my adhoc net using driver AR5211.SYS version 2.4.1.6.
2004-03-10 07:43:11 +00:00
if (duetime != NULL) {
tv.tv_sec -= (t2.tv_sec - t1.tv_sec);
tv.tv_usec -= (t2.tv_nsec - t1.tv_nsec) / 1000;
}
}
if (wcnt) {
for (i = 0; i < cnt; i++)
REMOVE_LIST_ENTRY((&w[i].wb_waitlist));
}
if (error == EWOULDBLOCK) {
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_unlock(&ntoskrnl_dispatchlock);
return(STATUS_TIMEOUT);
}
if (wtype == WAITTYPE_ANY && wcnt) {
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_unlock(&ntoskrnl_dispatchlock);
return(STATUS_WAIT_0 + widx);
}
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_unlock(&ntoskrnl_dispatchlock);
return(STATUS_SUCCESS);
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
}
__stdcall static void
ntoskrnl_writereg_ushort(reg, val)
uint16_t *reg;
uint16_t val;
{
bus_space_write_2(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg, val);
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
return;
}
__stdcall static uint16_t
ntoskrnl_readreg_ushort(reg)
uint16_t *reg;
{
return(bus_space_read_2(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg));
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
}
__stdcall static void
ntoskrnl_writereg_ulong(reg, val)
uint32_t *reg;
uint32_t val;
{
bus_space_write_4(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg, val);
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
return;
}
__stdcall static uint32_t
ntoskrnl_readreg_ulong(reg)
uint32_t *reg;
{
return(bus_space_read_4(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg));
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
}
__stdcall static uint8_t
ntoskrnl_readreg_uchar(reg)
uint8_t *reg;
{
return(bus_space_read_1(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg));
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
}
__stdcall static void
ntoskrnl_writereg_uchar(reg, val)
uint8_t *reg;
uint8_t val;
{
bus_space_write_1(NDIS_BUS_SPACE_MEM, 0x0, (bus_size_t)reg, val);
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
return;
}
__stdcall static int64_t
_allmul(a, b)
int64_t a;
int64_t b;
{
return (a * b);
}
__stdcall static int64_t
_alldiv(a, b)
int64_t a;
int64_t b;
{
return (a / b);
}
__stdcall static int64_t
_allrem(a, b)
int64_t a;
int64_t b;
{
return (a % b);
}
__stdcall static uint64_t
_aullmul(a, b)
uint64_t a;
uint64_t b;
{
return (a * b);
}
__stdcall static uint64_t
_aulldiv(a, b)
uint64_t a;
uint64_t b;
{
return (a / b);
}
__stdcall static uint64_t
_aullrem(a, b)
uint64_t a;
uint64_t b;
{
return (a % b);
}
__regparm static int64_t
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
_allshl(a, b)
int64_t a;
uint8_t b;
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
{
return (a << b);
}
__regparm static uint64_t
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
_aullshl(a, b)
uint64_t a;
uint8_t b;
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
{
return (a << b);
}
__regparm static int64_t
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
_allshr(a, b)
int64_t a;
uint8_t b;
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
{
return (a >> b);
}
__regparm static uint64_t
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
_aullshr(a, b)
uint64_t a;
uint8_t b;
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
{
return (a >> b);
}
static slist_entry *
ntoskrnl_pushsl(head, entry)
slist_header *head;
slist_entry *entry;
{
slist_entry *oldhead;
oldhead = head->slh_list.slh_next;
entry->sl_next = head->slh_list.slh_next;
head->slh_list.slh_next = entry;
head->slh_list.slh_depth++;
head->slh_list.slh_seq++;
return(oldhead);
}
static slist_entry *
ntoskrnl_popsl(head)
slist_header *head;
{
slist_entry *first;
first = head->slh_list.slh_next;
if (first != NULL) {
head->slh_list.slh_next = first->sl_next;
head->slh_list.slh_depth--;
head->slh_list.slh_seq++;
}
return(first);
}
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
__stdcall static void *
ntoskrnl_allocfunc(pooltype, size, tag)
uint32_t pooltype;
size_t size;
uint32_t tag;
{
return(malloc(size, M_DEVBUF, M_NOWAIT));
}
__stdcall static void
ntoskrnl_freefunc(buf)
void *buf;
{
free(buf, M_DEVBUF);
return;
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
}
__stdcall static void
ntoskrnl_init_lookaside(lookaside, allocfunc, freefunc,
flags, size, tag, depth)
paged_lookaside_list *lookaside;
lookaside_alloc_func *allocfunc;
lookaside_free_func *freefunc;
uint32_t flags;
size_t size;
uint32_t tag;
uint16_t depth;
{
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
bzero((char *)lookaside, sizeof(paged_lookaside_list));
Implement some more NDIS and ntoskrnl API calls: subr_ndis.c: NdisGetCurrentSystemTime() which, according to the Microsoft documentation returns "the number of 100 nanosecond intervals since January 1, 1601." I have no idea what's so special about that epoch or why they chose 100 nanosecond ticks. I don't know the proper offset to convert nanotime() from the UNIX epoch to January 1, 1601, so for now I'm just doing the unit convertion to 100s of nanoseconds. subr_ntoskrnl.c: memcpy(), memset(), ExInterlockedPopEntrySList(), ExInterlockedPushEntrySList(). The latter two are different from InterlockedPopEntrySList() and InterlockedPushEntrySList() in that they accept a spinlock to hold while executing, whereas the non-Ex routines use a lock internal to ntoskrnl. I also modified ExInitializePagedLookasideList() and ExInitializeNPagedLookasideList() to initialize mutex locks within the lookaside structures. It seems that in NDIS 5.0, the lookaside allocate/free routines ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(), which require the use of the per-lookaside spinlock, whereas in NDIS 5.1, the per-lookaside spinlock is deprecated. We need to support both cases. Note that I appear to be doing something wrong with ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(): they don't appear to obtain proper pointers to their arguments, so I'm probably doing something wrong in terms of their calling convention (they're declared to be FASTCALL in Widnows, and I'm not sure what that means for gcc). It happens that in my stub lookaside implementation, they don't need to do any work anyway, so for now I've hacked them to always return NULL, which avoids corrupting the stack. I need to do this right though.
2003-12-12 22:35:13 +00:00
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
if (size < sizeof(slist_entry))
lookaside->nll_l.gl_size = sizeof(slist_entry);
else
lookaside->nll_l.gl_size = size;
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
lookaside->nll_l.gl_tag = tag;
if (allocfunc == NULL)
lookaside->nll_l.gl_allocfunc = ntoskrnl_allocfunc;
else
lookaside->nll_l.gl_allocfunc = allocfunc;
if (freefunc == NULL)
lookaside->nll_l.gl_freefunc = ntoskrnl_freefunc;
else
lookaside->nll_l.gl_freefunc = freefunc;
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
ntoskrnl_init_lock(&lookaside->nll_obsoletelock);
Implement some more NDIS and ntoskrnl API calls: subr_ndis.c: NdisGetCurrentSystemTime() which, according to the Microsoft documentation returns "the number of 100 nanosecond intervals since January 1, 1601." I have no idea what's so special about that epoch or why they chose 100 nanosecond ticks. I don't know the proper offset to convert nanotime() from the UNIX epoch to January 1, 1601, so for now I'm just doing the unit convertion to 100s of nanoseconds. subr_ntoskrnl.c: memcpy(), memset(), ExInterlockedPopEntrySList(), ExInterlockedPushEntrySList(). The latter two are different from InterlockedPopEntrySList() and InterlockedPushEntrySList() in that they accept a spinlock to hold while executing, whereas the non-Ex routines use a lock internal to ntoskrnl. I also modified ExInitializePagedLookasideList() and ExInitializeNPagedLookasideList() to initialize mutex locks within the lookaside structures. It seems that in NDIS 5.0, the lookaside allocate/free routines ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(), which require the use of the per-lookaside spinlock, whereas in NDIS 5.1, the per-lookaside spinlock is deprecated. We need to support both cases. Note that I appear to be doing something wrong with ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(): they don't appear to obtain proper pointers to their arguments, so I'm probably doing something wrong in terms of their calling convention (they're declared to be FASTCALL in Widnows, and I'm not sure what that means for gcc). It happens that in my stub lookaside implementation, they don't need to do any work anyway, so for now I've hacked them to always return NULL, which avoids corrupting the stack. I need to do this right though.
2003-12-12 22:35:13 +00:00
lookaside->nll_l.gl_depth = LOOKASIDE_DEPTH;
lookaside->nll_l.gl_maxdepth = LOOKASIDE_DEPTH;
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
return;
}
__stdcall static void
ntoskrnl_delete_lookaside(lookaside)
paged_lookaside_list *lookaside;
{
void *buf;
__stdcall void (*freefunc)(void *);
freefunc = lookaside->nll_l.gl_freefunc;
while((buf = ntoskrnl_popsl(&lookaside->nll_l.gl_listhead)) != NULL)
freefunc(buf);
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
return;
}
__stdcall static void
ntoskrnl_init_nplookaside(lookaside, allocfunc, freefunc,
flags, size, tag, depth)
npaged_lookaside_list *lookaside;
lookaside_alloc_func *allocfunc;
lookaside_free_func *freefunc;
uint32_t flags;
size_t size;
uint32_t tag;
uint16_t depth;
{
bzero((char *)lookaside, sizeof(npaged_lookaside_list));
if (size < sizeof(slist_entry))
lookaside->nll_l.gl_size = sizeof(slist_entry);
else
lookaside->nll_l.gl_size = size;
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
lookaside->nll_l.gl_tag = tag;
if (allocfunc == NULL)
lookaside->nll_l.gl_allocfunc = ntoskrnl_allocfunc;
else
lookaside->nll_l.gl_allocfunc = allocfunc;
if (freefunc == NULL)
lookaside->nll_l.gl_freefunc = ntoskrnl_freefunc;
else
lookaside->nll_l.gl_freefunc = freefunc;
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
ntoskrnl_init_lock(&lookaside->nll_obsoletelock);
Implement some more NDIS and ntoskrnl API calls: subr_ndis.c: NdisGetCurrentSystemTime() which, according to the Microsoft documentation returns "the number of 100 nanosecond intervals since January 1, 1601." I have no idea what's so special about that epoch or why they chose 100 nanosecond ticks. I don't know the proper offset to convert nanotime() from the UNIX epoch to January 1, 1601, so for now I'm just doing the unit convertion to 100s of nanoseconds. subr_ntoskrnl.c: memcpy(), memset(), ExInterlockedPopEntrySList(), ExInterlockedPushEntrySList(). The latter two are different from InterlockedPopEntrySList() and InterlockedPushEntrySList() in that they accept a spinlock to hold while executing, whereas the non-Ex routines use a lock internal to ntoskrnl. I also modified ExInitializePagedLookasideList() and ExInitializeNPagedLookasideList() to initialize mutex locks within the lookaside structures. It seems that in NDIS 5.0, the lookaside allocate/free routines ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(), which require the use of the per-lookaside spinlock, whereas in NDIS 5.1, the per-lookaside spinlock is deprecated. We need to support both cases. Note that I appear to be doing something wrong with ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(): they don't appear to obtain proper pointers to their arguments, so I'm probably doing something wrong in terms of their calling convention (they're declared to be FASTCALL in Widnows, and I'm not sure what that means for gcc). It happens that in my stub lookaside implementation, they don't need to do any work anyway, so for now I've hacked them to always return NULL, which avoids corrupting the stack. I need to do this right though.
2003-12-12 22:35:13 +00:00
lookaside->nll_l.gl_depth = LOOKASIDE_DEPTH;
lookaside->nll_l.gl_maxdepth = LOOKASIDE_DEPTH;
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
return;
}
__stdcall static void
ntoskrnl_delete_nplookaside(lookaside)
npaged_lookaside_list *lookaside;
{
void *buf;
__stdcall void (*freefunc)(void *);
freefunc = lookaside->nll_l.gl_freefunc;
while((buf = ntoskrnl_popsl(&lookaside->nll_l.gl_listhead)) != NULL)
freefunc(buf);
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
return;
}
/*
* Note: the interlocked slist push and pop routines are
subr_ndis.c: - fix ndis_time() so that it returns a time based on the proper epoch (wacky though it may be) - implement NdisInitializeString() and NdisFreeString(), and add stub for NdisMRemoveMiniport() ntoskrnl_var.h: - add missing member to the general_lookaside struct (gl_listentry) subr_ntoskrnl.c: - Fix arguments to the interlocked push/pop routines: 'head' is an slist_header *, not an slist_entry * - Kludge up _fastcall support for the push/pop routines. The _fastcall convention is similar to _stdcall, except the first two available DWORD-sized arguments are passed in %ecx and %edx, respectively. One kludge for this __attribute__ ((regparm(3))), however this isn't entirely right, as it assumes %eax, %ecx and %edx will be used (regparm(2) assumes %eax and %edx). Another kludge is to declare the two fastcall-ed args as local register variables and explicitly assign them to %ecx and %edx, but experimentation showed that gcc would not guard %ecx and %edx against being clobbered. Thus, I came up with a 3rd kludge, which is to use some inline assembly of the form: void *arg1; void *arg2; __asm__("movl %%ecx, %%ecx" : "=c" (arg1)); __asm__("movl %%edx, %%edx" : "=d" (arg2)); This lets gcc know that we're going to reference %ecx and %edx and that it should make an effort not to let it get trampled. This wastes an instruction (movl %reg, %reg is a no-op) but insures proper behavior. It's possible there's a better way to do this though: this is the first time I've used inline assembler in this fashion. The above fixes to ntoskrnl_var.h an subr_ntoskrnl.c make lookaside lists work for the two drivers I have that use them, one of which is an NDIS 5.0 miniport and another which is 5.1.
2003-12-13 07:41:12 +00:00
* declared to be _fastcall in Windows. gcc 3.4 is supposed
* to have support for this calling convention, however we
* don't have that version available yet, so we kludge things
* up using some inline assembly.
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
*/
subr_ndis.c: - fix ndis_time() so that it returns a time based on the proper epoch (wacky though it may be) - implement NdisInitializeString() and NdisFreeString(), and add stub for NdisMRemoveMiniport() ntoskrnl_var.h: - add missing member to the general_lookaside struct (gl_listentry) subr_ntoskrnl.c: - Fix arguments to the interlocked push/pop routines: 'head' is an slist_header *, not an slist_entry * - Kludge up _fastcall support for the push/pop routines. The _fastcall convention is similar to _stdcall, except the first two available DWORD-sized arguments are passed in %ecx and %edx, respectively. One kludge for this __attribute__ ((regparm(3))), however this isn't entirely right, as it assumes %eax, %ecx and %edx will be used (regparm(2) assumes %eax and %edx). Another kludge is to declare the two fastcall-ed args as local register variables and explicitly assign them to %ecx and %edx, but experimentation showed that gcc would not guard %ecx and %edx against being clobbered. Thus, I came up with a 3rd kludge, which is to use some inline assembly of the form: void *arg1; void *arg2; __asm__("movl %%ecx, %%ecx" : "=c" (arg1)); __asm__("movl %%edx, %%edx" : "=d" (arg2)); This lets gcc know that we're going to reference %ecx and %edx and that it should make an effort not to let it get trampled. This wastes an instruction (movl %reg, %reg is a no-op) but insures proper behavior. It's possible there's a better way to do this though: this is the first time I've used inline assembler in this fashion. The above fixes to ntoskrnl_var.h an subr_ntoskrnl.c make lookaside lists work for the two drivers I have that use them, one of which is an NDIS 5.0 miniport and another which is 5.1.
2003-12-13 07:41:12 +00:00
__stdcall static slist_entry *
ntoskrnl_push_slist(/*head, entry*/ void)
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
{
subr_ndis.c: - fix ndis_time() so that it returns a time based on the proper epoch (wacky though it may be) - implement NdisInitializeString() and NdisFreeString(), and add stub for NdisMRemoveMiniport() ntoskrnl_var.h: - add missing member to the general_lookaside struct (gl_listentry) subr_ntoskrnl.c: - Fix arguments to the interlocked push/pop routines: 'head' is an slist_header *, not an slist_entry * - Kludge up _fastcall support for the push/pop routines. The _fastcall convention is similar to _stdcall, except the first two available DWORD-sized arguments are passed in %ecx and %edx, respectively. One kludge for this __attribute__ ((regparm(3))), however this isn't entirely right, as it assumes %eax, %ecx and %edx will be used (regparm(2) assumes %eax and %edx). Another kludge is to declare the two fastcall-ed args as local register variables and explicitly assign them to %ecx and %edx, but experimentation showed that gcc would not guard %ecx and %edx against being clobbered. Thus, I came up with a 3rd kludge, which is to use some inline assembly of the form: void *arg1; void *arg2; __asm__("movl %%ecx, %%ecx" : "=c" (arg1)); __asm__("movl %%edx, %%edx" : "=d" (arg2)); This lets gcc know that we're going to reference %ecx and %edx and that it should make an effort not to let it get trampled. This wastes an instruction (movl %reg, %reg is a no-op) but insures proper behavior. It's possible there's a better way to do this though: this is the first time I've used inline assembler in this fashion. The above fixes to ntoskrnl_var.h an subr_ntoskrnl.c make lookaside lists work for the two drivers I have that use them, one of which is an NDIS 5.0 miniport and another which is 5.1.
2003-12-13 07:41:12 +00:00
slist_header *head;
slist_entry *entry;
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
slist_entry *oldhead;
subr_ndis.c: - fix ndis_time() so that it returns a time based on the proper epoch (wacky though it may be) - implement NdisInitializeString() and NdisFreeString(), and add stub for NdisMRemoveMiniport() ntoskrnl_var.h: - add missing member to the general_lookaside struct (gl_listentry) subr_ntoskrnl.c: - Fix arguments to the interlocked push/pop routines: 'head' is an slist_header *, not an slist_entry * - Kludge up _fastcall support for the push/pop routines. The _fastcall convention is similar to _stdcall, except the first two available DWORD-sized arguments are passed in %ecx and %edx, respectively. One kludge for this __attribute__ ((regparm(3))), however this isn't entirely right, as it assumes %eax, %ecx and %edx will be used (regparm(2) assumes %eax and %edx). Another kludge is to declare the two fastcall-ed args as local register variables and explicitly assign them to %ecx and %edx, but experimentation showed that gcc would not guard %ecx and %edx against being clobbered. Thus, I came up with a 3rd kludge, which is to use some inline assembly of the form: void *arg1; void *arg2; __asm__("movl %%ecx, %%ecx" : "=c" (arg1)); __asm__("movl %%edx, %%edx" : "=d" (arg2)); This lets gcc know that we're going to reference %ecx and %edx and that it should make an effort not to let it get trampled. This wastes an instruction (movl %reg, %reg is a no-op) but insures proper behavior. It's possible there's a better way to do this though: this is the first time I've used inline assembler in this fashion. The above fixes to ntoskrnl_var.h an subr_ntoskrnl.c make lookaside lists work for the two drivers I have that use them, one of which is an NDIS 5.0 miniport and another which is 5.1.
2003-12-13 07:41:12 +00:00
__asm__ __volatile__ ("" : "=c" (head), "=d" (entry));
subr_ndis.c: - fix ndis_time() so that it returns a time based on the proper epoch (wacky though it may be) - implement NdisInitializeString() and NdisFreeString(), and add stub for NdisMRemoveMiniport() ntoskrnl_var.h: - add missing member to the general_lookaside struct (gl_listentry) subr_ntoskrnl.c: - Fix arguments to the interlocked push/pop routines: 'head' is an slist_header *, not an slist_entry * - Kludge up _fastcall support for the push/pop routines. The _fastcall convention is similar to _stdcall, except the first two available DWORD-sized arguments are passed in %ecx and %edx, respectively. One kludge for this __attribute__ ((regparm(3))), however this isn't entirely right, as it assumes %eax, %ecx and %edx will be used (regparm(2) assumes %eax and %edx). Another kludge is to declare the two fastcall-ed args as local register variables and explicitly assign them to %ecx and %edx, but experimentation showed that gcc would not guard %ecx and %edx against being clobbered. Thus, I came up with a 3rd kludge, which is to use some inline assembly of the form: void *arg1; void *arg2; __asm__("movl %%ecx, %%ecx" : "=c" (arg1)); __asm__("movl %%edx, %%edx" : "=d" (arg2)); This lets gcc know that we're going to reference %ecx and %edx and that it should make an effort not to let it get trampled. This wastes an instruction (movl %reg, %reg is a no-op) but insures proper behavior. It's possible there's a better way to do this though: this is the first time I've used inline assembler in this fashion. The above fixes to ntoskrnl_var.h an subr_ntoskrnl.c make lookaside lists work for the two drivers I have that use them, one of which is an NDIS 5.0 miniport and another which is 5.1.
2003-12-13 07:41:12 +00:00
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
oldhead = (slist_entry *)FASTCALL3(ntoskrnl_push_slist_ex,
head, entry, &ntoskrnl_global);
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
return(oldhead);
}
subr_ndis.c: - fix ndis_time() so that it returns a time based on the proper epoch (wacky though it may be) - implement NdisInitializeString() and NdisFreeString(), and add stub for NdisMRemoveMiniport() ntoskrnl_var.h: - add missing member to the general_lookaside struct (gl_listentry) subr_ntoskrnl.c: - Fix arguments to the interlocked push/pop routines: 'head' is an slist_header *, not an slist_entry * - Kludge up _fastcall support for the push/pop routines. The _fastcall convention is similar to _stdcall, except the first two available DWORD-sized arguments are passed in %ecx and %edx, respectively. One kludge for this __attribute__ ((regparm(3))), however this isn't entirely right, as it assumes %eax, %ecx and %edx will be used (regparm(2) assumes %eax and %edx). Another kludge is to declare the two fastcall-ed args as local register variables and explicitly assign them to %ecx and %edx, but experimentation showed that gcc would not guard %ecx and %edx against being clobbered. Thus, I came up with a 3rd kludge, which is to use some inline assembly of the form: void *arg1; void *arg2; __asm__("movl %%ecx, %%ecx" : "=c" (arg1)); __asm__("movl %%edx, %%edx" : "=d" (arg2)); This lets gcc know that we're going to reference %ecx and %edx and that it should make an effort not to let it get trampled. This wastes an instruction (movl %reg, %reg is a no-op) but insures proper behavior. It's possible there's a better way to do this though: this is the first time I've used inline assembler in this fashion. The above fixes to ntoskrnl_var.h an subr_ntoskrnl.c make lookaside lists work for the two drivers I have that use them, one of which is an NDIS 5.0 miniport and another which is 5.1.
2003-12-13 07:41:12 +00:00
__stdcall static slist_entry *
ntoskrnl_pop_slist(/*head*/ void)
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
{
subr_ndis.c: - fix ndis_time() so that it returns a time based on the proper epoch (wacky though it may be) - implement NdisInitializeString() and NdisFreeString(), and add stub for NdisMRemoveMiniport() ntoskrnl_var.h: - add missing member to the general_lookaside struct (gl_listentry) subr_ntoskrnl.c: - Fix arguments to the interlocked push/pop routines: 'head' is an slist_header *, not an slist_entry * - Kludge up _fastcall support for the push/pop routines. The _fastcall convention is similar to _stdcall, except the first two available DWORD-sized arguments are passed in %ecx and %edx, respectively. One kludge for this __attribute__ ((regparm(3))), however this isn't entirely right, as it assumes %eax, %ecx and %edx will be used (regparm(2) assumes %eax and %edx). Another kludge is to declare the two fastcall-ed args as local register variables and explicitly assign them to %ecx and %edx, but experimentation showed that gcc would not guard %ecx and %edx against being clobbered. Thus, I came up with a 3rd kludge, which is to use some inline assembly of the form: void *arg1; void *arg2; __asm__("movl %%ecx, %%ecx" : "=c" (arg1)); __asm__("movl %%edx, %%edx" : "=d" (arg2)); This lets gcc know that we're going to reference %ecx and %edx and that it should make an effort not to let it get trampled. This wastes an instruction (movl %reg, %reg is a no-op) but insures proper behavior. It's possible there's a better way to do this though: this is the first time I've used inline assembler in this fashion. The above fixes to ntoskrnl_var.h an subr_ntoskrnl.c make lookaside lists work for the two drivers I have that use them, one of which is an NDIS 5.0 miniport and another which is 5.1.
2003-12-13 07:41:12 +00:00
slist_header *head;
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
slist_entry *first;
subr_ndis.c: - fix ndis_time() so that it returns a time based on the proper epoch (wacky though it may be) - implement NdisInitializeString() and NdisFreeString(), and add stub for NdisMRemoveMiniport() ntoskrnl_var.h: - add missing member to the general_lookaside struct (gl_listentry) subr_ntoskrnl.c: - Fix arguments to the interlocked push/pop routines: 'head' is an slist_header *, not an slist_entry * - Kludge up _fastcall support for the push/pop routines. The _fastcall convention is similar to _stdcall, except the first two available DWORD-sized arguments are passed in %ecx and %edx, respectively. One kludge for this __attribute__ ((regparm(3))), however this isn't entirely right, as it assumes %eax, %ecx and %edx will be used (regparm(2) assumes %eax and %edx). Another kludge is to declare the two fastcall-ed args as local register variables and explicitly assign them to %ecx and %edx, but experimentation showed that gcc would not guard %ecx and %edx against being clobbered. Thus, I came up with a 3rd kludge, which is to use some inline assembly of the form: void *arg1; void *arg2; __asm__("movl %%ecx, %%ecx" : "=c" (arg1)); __asm__("movl %%edx, %%edx" : "=d" (arg2)); This lets gcc know that we're going to reference %ecx and %edx and that it should make an effort not to let it get trampled. This wastes an instruction (movl %reg, %reg is a no-op) but insures proper behavior. It's possible there's a better way to do this though: this is the first time I've used inline assembler in this fashion. The above fixes to ntoskrnl_var.h an subr_ntoskrnl.c make lookaside lists work for the two drivers I have that use them, one of which is an NDIS 5.0 miniport and another which is 5.1.
2003-12-13 07:41:12 +00:00
__asm__ __volatile__ ("" : "=c" (head));
subr_ndis.c: - fix ndis_time() so that it returns a time based on the proper epoch (wacky though it may be) - implement NdisInitializeString() and NdisFreeString(), and add stub for NdisMRemoveMiniport() ntoskrnl_var.h: - add missing member to the general_lookaside struct (gl_listentry) subr_ntoskrnl.c: - Fix arguments to the interlocked push/pop routines: 'head' is an slist_header *, not an slist_entry * - Kludge up _fastcall support for the push/pop routines. The _fastcall convention is similar to _stdcall, except the first two available DWORD-sized arguments are passed in %ecx and %edx, respectively. One kludge for this __attribute__ ((regparm(3))), however this isn't entirely right, as it assumes %eax, %ecx and %edx will be used (regparm(2) assumes %eax and %edx). Another kludge is to declare the two fastcall-ed args as local register variables and explicitly assign them to %ecx and %edx, but experimentation showed that gcc would not guard %ecx and %edx against being clobbered. Thus, I came up with a 3rd kludge, which is to use some inline assembly of the form: void *arg1; void *arg2; __asm__("movl %%ecx, %%ecx" : "=c" (arg1)); __asm__("movl %%edx, %%edx" : "=d" (arg2)); This lets gcc know that we're going to reference %ecx and %edx and that it should make an effort not to let it get trampled. This wastes an instruction (movl %reg, %reg is a no-op) but insures proper behavior. It's possible there's a better way to do this though: this is the first time I've used inline assembler in this fashion. The above fixes to ntoskrnl_var.h an subr_ntoskrnl.c make lookaside lists work for the two drivers I have that use them, one of which is an NDIS 5.0 miniport and another which is 5.1.
2003-12-13 07:41:12 +00:00
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
first = (slist_entry *)FASTCALL2(ntoskrnl_pop_slist_ex,
head, &ntoskrnl_global);
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
return(first);
}
Implement some more NDIS and ntoskrnl API calls: subr_ndis.c: NdisGetCurrentSystemTime() which, according to the Microsoft documentation returns "the number of 100 nanosecond intervals since January 1, 1601." I have no idea what's so special about that epoch or why they chose 100 nanosecond ticks. I don't know the proper offset to convert nanotime() from the UNIX epoch to January 1, 1601, so for now I'm just doing the unit convertion to 100s of nanoseconds. subr_ntoskrnl.c: memcpy(), memset(), ExInterlockedPopEntrySList(), ExInterlockedPushEntrySList(). The latter two are different from InterlockedPopEntrySList() and InterlockedPushEntrySList() in that they accept a spinlock to hold while executing, whereas the non-Ex routines use a lock internal to ntoskrnl. I also modified ExInitializePagedLookasideList() and ExInitializeNPagedLookasideList() to initialize mutex locks within the lookaside structures. It seems that in NDIS 5.0, the lookaside allocate/free routines ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(), which require the use of the per-lookaside spinlock, whereas in NDIS 5.1, the per-lookaside spinlock is deprecated. We need to support both cases. Note that I appear to be doing something wrong with ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(): they don't appear to obtain proper pointers to their arguments, so I'm probably doing something wrong in terms of their calling convention (they're declared to be FASTCALL in Widnows, and I'm not sure what that means for gcc). It happens that in my stub lookaside implementation, they don't need to do any work anyway, so for now I've hacked them to always return NULL, which avoids corrupting the stack. I need to do this right though.
2003-12-12 22:35:13 +00:00
__stdcall static slist_entry *
subr_ndis.c: - fix ndis_time() so that it returns a time based on the proper epoch (wacky though it may be) - implement NdisInitializeString() and NdisFreeString(), and add stub for NdisMRemoveMiniport() ntoskrnl_var.h: - add missing member to the general_lookaside struct (gl_listentry) subr_ntoskrnl.c: - Fix arguments to the interlocked push/pop routines: 'head' is an slist_header *, not an slist_entry * - Kludge up _fastcall support for the push/pop routines. The _fastcall convention is similar to _stdcall, except the first two available DWORD-sized arguments are passed in %ecx and %edx, respectively. One kludge for this __attribute__ ((regparm(3))), however this isn't entirely right, as it assumes %eax, %ecx and %edx will be used (regparm(2) assumes %eax and %edx). Another kludge is to declare the two fastcall-ed args as local register variables and explicitly assign them to %ecx and %edx, but experimentation showed that gcc would not guard %ecx and %edx against being clobbered. Thus, I came up with a 3rd kludge, which is to use some inline assembly of the form: void *arg1; void *arg2; __asm__("movl %%ecx, %%ecx" : "=c" (arg1)); __asm__("movl %%edx, %%edx" : "=d" (arg2)); This lets gcc know that we're going to reference %ecx and %edx and that it should make an effort not to let it get trampled. This wastes an instruction (movl %reg, %reg is a no-op) but insures proper behavior. It's possible there's a better way to do this though: this is the first time I've used inline assembler in this fashion. The above fixes to ntoskrnl_var.h an subr_ntoskrnl.c make lookaside lists work for the two drivers I have that use them, one of which is an NDIS 5.0 miniport and another which is 5.1.
2003-12-13 07:41:12 +00:00
ntoskrnl_push_slist_ex(/*head, entry,*/ lock)
Implement some more NDIS and ntoskrnl API calls: subr_ndis.c: NdisGetCurrentSystemTime() which, according to the Microsoft documentation returns "the number of 100 nanosecond intervals since January 1, 1601." I have no idea what's so special about that epoch or why they chose 100 nanosecond ticks. I don't know the proper offset to convert nanotime() from the UNIX epoch to January 1, 1601, so for now I'm just doing the unit convertion to 100s of nanoseconds. subr_ntoskrnl.c: memcpy(), memset(), ExInterlockedPopEntrySList(), ExInterlockedPushEntrySList(). The latter two are different from InterlockedPopEntrySList() and InterlockedPushEntrySList() in that they accept a spinlock to hold while executing, whereas the non-Ex routines use a lock internal to ntoskrnl. I also modified ExInitializePagedLookasideList() and ExInitializeNPagedLookasideList() to initialize mutex locks within the lookaside structures. It seems that in NDIS 5.0, the lookaside allocate/free routines ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(), which require the use of the per-lookaside spinlock, whereas in NDIS 5.1, the per-lookaside spinlock is deprecated. We need to support both cases. Note that I appear to be doing something wrong with ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(): they don't appear to obtain proper pointers to their arguments, so I'm probably doing something wrong in terms of their calling convention (they're declared to be FASTCALL in Widnows, and I'm not sure what that means for gcc). It happens that in my stub lookaside implementation, they don't need to do any work anyway, so for now I've hacked them to always return NULL, which avoids corrupting the stack. I need to do this right though.
2003-12-12 22:35:13 +00:00
kspin_lock *lock;
{
subr_ndis.c: - fix ndis_time() so that it returns a time based on the proper epoch (wacky though it may be) - implement NdisInitializeString() and NdisFreeString(), and add stub for NdisMRemoveMiniport() ntoskrnl_var.h: - add missing member to the general_lookaside struct (gl_listentry) subr_ntoskrnl.c: - Fix arguments to the interlocked push/pop routines: 'head' is an slist_header *, not an slist_entry * - Kludge up _fastcall support for the push/pop routines. The _fastcall convention is similar to _stdcall, except the first two available DWORD-sized arguments are passed in %ecx and %edx, respectively. One kludge for this __attribute__ ((regparm(3))), however this isn't entirely right, as it assumes %eax, %ecx and %edx will be used (regparm(2) assumes %eax and %edx). Another kludge is to declare the two fastcall-ed args as local register variables and explicitly assign them to %ecx and %edx, but experimentation showed that gcc would not guard %ecx and %edx against being clobbered. Thus, I came up with a 3rd kludge, which is to use some inline assembly of the form: void *arg1; void *arg2; __asm__("movl %%ecx, %%ecx" : "=c" (arg1)); __asm__("movl %%edx, %%edx" : "=d" (arg2)); This lets gcc know that we're going to reference %ecx and %edx and that it should make an effort not to let it get trampled. This wastes an instruction (movl %reg, %reg is a no-op) but insures proper behavior. It's possible there's a better way to do this though: this is the first time I've used inline assembler in this fashion. The above fixes to ntoskrnl_var.h an subr_ntoskrnl.c make lookaside lists work for the two drivers I have that use them, one of which is an NDIS 5.0 miniport and another which is 5.1.
2003-12-13 07:41:12 +00:00
slist_header *head;
slist_entry *entry;
Implement some more NDIS and ntoskrnl API calls: subr_ndis.c: NdisGetCurrentSystemTime() which, according to the Microsoft documentation returns "the number of 100 nanosecond intervals since January 1, 1601." I have no idea what's so special about that epoch or why they chose 100 nanosecond ticks. I don't know the proper offset to convert nanotime() from the UNIX epoch to January 1, 1601, so for now I'm just doing the unit convertion to 100s of nanoseconds. subr_ntoskrnl.c: memcpy(), memset(), ExInterlockedPopEntrySList(), ExInterlockedPushEntrySList(). The latter two are different from InterlockedPopEntrySList() and InterlockedPushEntrySList() in that they accept a spinlock to hold while executing, whereas the non-Ex routines use a lock internal to ntoskrnl. I also modified ExInitializePagedLookasideList() and ExInitializeNPagedLookasideList() to initialize mutex locks within the lookaside structures. It seems that in NDIS 5.0, the lookaside allocate/free routines ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(), which require the use of the per-lookaside spinlock, whereas in NDIS 5.1, the per-lookaside spinlock is deprecated. We need to support both cases. Note that I appear to be doing something wrong with ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(): they don't appear to obtain proper pointers to their arguments, so I'm probably doing something wrong in terms of their calling convention (they're declared to be FASTCALL in Widnows, and I'm not sure what that means for gcc). It happens that in my stub lookaside implementation, they don't need to do any work anyway, so for now I've hacked them to always return NULL, which avoids corrupting the stack. I need to do this right though.
2003-12-12 22:35:13 +00:00
slist_entry *oldhead;
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
uint8_t irql;
subr_ndis.c: - fix ndis_time() so that it returns a time based on the proper epoch (wacky though it may be) - implement NdisInitializeString() and NdisFreeString(), and add stub for NdisMRemoveMiniport() ntoskrnl_var.h: - add missing member to the general_lookaside struct (gl_listentry) subr_ntoskrnl.c: - Fix arguments to the interlocked push/pop routines: 'head' is an slist_header *, not an slist_entry * - Kludge up _fastcall support for the push/pop routines. The _fastcall convention is similar to _stdcall, except the first two available DWORD-sized arguments are passed in %ecx and %edx, respectively. One kludge for this __attribute__ ((regparm(3))), however this isn't entirely right, as it assumes %eax, %ecx and %edx will be used (regparm(2) assumes %eax and %edx). Another kludge is to declare the two fastcall-ed args as local register variables and explicitly assign them to %ecx and %edx, but experimentation showed that gcc would not guard %ecx and %edx against being clobbered. Thus, I came up with a 3rd kludge, which is to use some inline assembly of the form: void *arg1; void *arg2; __asm__("movl %%ecx, %%ecx" : "=c" (arg1)); __asm__("movl %%edx, %%edx" : "=d" (arg2)); This lets gcc know that we're going to reference %ecx and %edx and that it should make an effort not to let it get trampled. This wastes an instruction (movl %reg, %reg is a no-op) but insures proper behavior. It's possible there's a better way to do this though: this is the first time I've used inline assembler in this fashion. The above fixes to ntoskrnl_var.h an subr_ntoskrnl.c make lookaside lists work for the two drivers I have that use them, one of which is an NDIS 5.0 miniport and another which is 5.1.
2003-12-13 07:41:12 +00:00
__asm__ __volatile__ ("" : "=c" (head), "=d" (entry));
subr_ndis.c: - fix ndis_time() so that it returns a time based on the proper epoch (wacky though it may be) - implement NdisInitializeString() and NdisFreeString(), and add stub for NdisMRemoveMiniport() ntoskrnl_var.h: - add missing member to the general_lookaside struct (gl_listentry) subr_ntoskrnl.c: - Fix arguments to the interlocked push/pop routines: 'head' is an slist_header *, not an slist_entry * - Kludge up _fastcall support for the push/pop routines. The _fastcall convention is similar to _stdcall, except the first two available DWORD-sized arguments are passed in %ecx and %edx, respectively. One kludge for this __attribute__ ((regparm(3))), however this isn't entirely right, as it assumes %eax, %ecx and %edx will be used (regparm(2) assumes %eax and %edx). Another kludge is to declare the two fastcall-ed args as local register variables and explicitly assign them to %ecx and %edx, but experimentation showed that gcc would not guard %ecx and %edx against being clobbered. Thus, I came up with a 3rd kludge, which is to use some inline assembly of the form: void *arg1; void *arg2; __asm__("movl %%ecx, %%ecx" : "=c" (arg1)); __asm__("movl %%edx, %%edx" : "=d" (arg2)); This lets gcc know that we're going to reference %ecx and %edx and that it should make an effort not to let it get trampled. This wastes an instruction (movl %reg, %reg is a no-op) but insures proper behavior. It's possible there's a better way to do this though: this is the first time I've used inline assembler in this fashion. The above fixes to ntoskrnl_var.h an subr_ntoskrnl.c make lookaside lists work for the two drivers I have that use them, one of which is an NDIS 5.0 miniport and another which is 5.1.
2003-12-13 07:41:12 +00:00
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
irql = FASTCALL2(hal_lock, lock, DISPATCH_LEVEL);
oldhead = ntoskrnl_pushsl(head, entry);
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
FASTCALL2(hal_unlock, lock, irql);
Implement some more NDIS and ntoskrnl API calls: subr_ndis.c: NdisGetCurrentSystemTime() which, according to the Microsoft documentation returns "the number of 100 nanosecond intervals since January 1, 1601." I have no idea what's so special about that epoch or why they chose 100 nanosecond ticks. I don't know the proper offset to convert nanotime() from the UNIX epoch to January 1, 1601, so for now I'm just doing the unit convertion to 100s of nanoseconds. subr_ntoskrnl.c: memcpy(), memset(), ExInterlockedPopEntrySList(), ExInterlockedPushEntrySList(). The latter two are different from InterlockedPopEntrySList() and InterlockedPushEntrySList() in that they accept a spinlock to hold while executing, whereas the non-Ex routines use a lock internal to ntoskrnl. I also modified ExInitializePagedLookasideList() and ExInitializeNPagedLookasideList() to initialize mutex locks within the lookaside structures. It seems that in NDIS 5.0, the lookaside allocate/free routines ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(), which require the use of the per-lookaside spinlock, whereas in NDIS 5.1, the per-lookaside spinlock is deprecated. We need to support both cases. Note that I appear to be doing something wrong with ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(): they don't appear to obtain proper pointers to their arguments, so I'm probably doing something wrong in terms of their calling convention (they're declared to be FASTCALL in Widnows, and I'm not sure what that means for gcc). It happens that in my stub lookaside implementation, they don't need to do any work anyway, so for now I've hacked them to always return NULL, which avoids corrupting the stack. I need to do this right though.
2003-12-12 22:35:13 +00:00
return(oldhead);
}
__stdcall static slist_entry *
subr_ndis.c: - fix ndis_time() so that it returns a time based on the proper epoch (wacky though it may be) - implement NdisInitializeString() and NdisFreeString(), and add stub for NdisMRemoveMiniport() ntoskrnl_var.h: - add missing member to the general_lookaside struct (gl_listentry) subr_ntoskrnl.c: - Fix arguments to the interlocked push/pop routines: 'head' is an slist_header *, not an slist_entry * - Kludge up _fastcall support for the push/pop routines. The _fastcall convention is similar to _stdcall, except the first two available DWORD-sized arguments are passed in %ecx and %edx, respectively. One kludge for this __attribute__ ((regparm(3))), however this isn't entirely right, as it assumes %eax, %ecx and %edx will be used (regparm(2) assumes %eax and %edx). Another kludge is to declare the two fastcall-ed args as local register variables and explicitly assign them to %ecx and %edx, but experimentation showed that gcc would not guard %ecx and %edx against being clobbered. Thus, I came up with a 3rd kludge, which is to use some inline assembly of the form: void *arg1; void *arg2; __asm__("movl %%ecx, %%ecx" : "=c" (arg1)); __asm__("movl %%edx, %%edx" : "=d" (arg2)); This lets gcc know that we're going to reference %ecx and %edx and that it should make an effort not to let it get trampled. This wastes an instruction (movl %reg, %reg is a no-op) but insures proper behavior. It's possible there's a better way to do this though: this is the first time I've used inline assembler in this fashion. The above fixes to ntoskrnl_var.h an subr_ntoskrnl.c make lookaside lists work for the two drivers I have that use them, one of which is an NDIS 5.0 miniport and another which is 5.1.
2003-12-13 07:41:12 +00:00
ntoskrnl_pop_slist_ex(/*head, lock*/ void)
Implement some more NDIS and ntoskrnl API calls: subr_ndis.c: NdisGetCurrentSystemTime() which, according to the Microsoft documentation returns "the number of 100 nanosecond intervals since January 1, 1601." I have no idea what's so special about that epoch or why they chose 100 nanosecond ticks. I don't know the proper offset to convert nanotime() from the UNIX epoch to January 1, 1601, so for now I'm just doing the unit convertion to 100s of nanoseconds. subr_ntoskrnl.c: memcpy(), memset(), ExInterlockedPopEntrySList(), ExInterlockedPushEntrySList(). The latter two are different from InterlockedPopEntrySList() and InterlockedPushEntrySList() in that they accept a spinlock to hold while executing, whereas the non-Ex routines use a lock internal to ntoskrnl. I also modified ExInitializePagedLookasideList() and ExInitializeNPagedLookasideList() to initialize mutex locks within the lookaside structures. It seems that in NDIS 5.0, the lookaside allocate/free routines ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(), which require the use of the per-lookaside spinlock, whereas in NDIS 5.1, the per-lookaside spinlock is deprecated. We need to support both cases. Note that I appear to be doing something wrong with ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(): they don't appear to obtain proper pointers to their arguments, so I'm probably doing something wrong in terms of their calling convention (they're declared to be FASTCALL in Widnows, and I'm not sure what that means for gcc). It happens that in my stub lookaside implementation, they don't need to do any work anyway, so for now I've hacked them to always return NULL, which avoids corrupting the stack. I need to do this right though.
2003-12-12 22:35:13 +00:00
{
subr_ndis.c: - fix ndis_time() so that it returns a time based on the proper epoch (wacky though it may be) - implement NdisInitializeString() and NdisFreeString(), and add stub for NdisMRemoveMiniport() ntoskrnl_var.h: - add missing member to the general_lookaside struct (gl_listentry) subr_ntoskrnl.c: - Fix arguments to the interlocked push/pop routines: 'head' is an slist_header *, not an slist_entry * - Kludge up _fastcall support for the push/pop routines. The _fastcall convention is similar to _stdcall, except the first two available DWORD-sized arguments are passed in %ecx and %edx, respectively. One kludge for this __attribute__ ((regparm(3))), however this isn't entirely right, as it assumes %eax, %ecx and %edx will be used (regparm(2) assumes %eax and %edx). Another kludge is to declare the two fastcall-ed args as local register variables and explicitly assign them to %ecx and %edx, but experimentation showed that gcc would not guard %ecx and %edx against being clobbered. Thus, I came up with a 3rd kludge, which is to use some inline assembly of the form: void *arg1; void *arg2; __asm__("movl %%ecx, %%ecx" : "=c" (arg1)); __asm__("movl %%edx, %%edx" : "=d" (arg2)); This lets gcc know that we're going to reference %ecx and %edx and that it should make an effort not to let it get trampled. This wastes an instruction (movl %reg, %reg is a no-op) but insures proper behavior. It's possible there's a better way to do this though: this is the first time I've used inline assembler in this fashion. The above fixes to ntoskrnl_var.h an subr_ntoskrnl.c make lookaside lists work for the two drivers I have that use them, one of which is an NDIS 5.0 miniport and another which is 5.1.
2003-12-13 07:41:12 +00:00
slist_header *head;
kspin_lock *lock;
Implement some more NDIS and ntoskrnl API calls: subr_ndis.c: NdisGetCurrentSystemTime() which, according to the Microsoft documentation returns "the number of 100 nanosecond intervals since January 1, 1601." I have no idea what's so special about that epoch or why they chose 100 nanosecond ticks. I don't know the proper offset to convert nanotime() from the UNIX epoch to January 1, 1601, so for now I'm just doing the unit convertion to 100s of nanoseconds. subr_ntoskrnl.c: memcpy(), memset(), ExInterlockedPopEntrySList(), ExInterlockedPushEntrySList(). The latter two are different from InterlockedPopEntrySList() and InterlockedPushEntrySList() in that they accept a spinlock to hold while executing, whereas the non-Ex routines use a lock internal to ntoskrnl. I also modified ExInitializePagedLookasideList() and ExInitializeNPagedLookasideList() to initialize mutex locks within the lookaside structures. It seems that in NDIS 5.0, the lookaside allocate/free routines ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(), which require the use of the per-lookaside spinlock, whereas in NDIS 5.1, the per-lookaside spinlock is deprecated. We need to support both cases. Note that I appear to be doing something wrong with ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(): they don't appear to obtain proper pointers to their arguments, so I'm probably doing something wrong in terms of their calling convention (they're declared to be FASTCALL in Widnows, and I'm not sure what that means for gcc). It happens that in my stub lookaside implementation, they don't need to do any work anyway, so for now I've hacked them to always return NULL, which avoids corrupting the stack. I need to do this right though.
2003-12-12 22:35:13 +00:00
slist_entry *first;
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
uint8_t irql;
Implement some more NDIS and ntoskrnl API calls: subr_ndis.c: NdisGetCurrentSystemTime() which, according to the Microsoft documentation returns "the number of 100 nanosecond intervals since January 1, 1601." I have no idea what's so special about that epoch or why they chose 100 nanosecond ticks. I don't know the proper offset to convert nanotime() from the UNIX epoch to January 1, 1601, so for now I'm just doing the unit convertion to 100s of nanoseconds. subr_ntoskrnl.c: memcpy(), memset(), ExInterlockedPopEntrySList(), ExInterlockedPushEntrySList(). The latter two are different from InterlockedPopEntrySList() and InterlockedPushEntrySList() in that they accept a spinlock to hold while executing, whereas the non-Ex routines use a lock internal to ntoskrnl. I also modified ExInitializePagedLookasideList() and ExInitializeNPagedLookasideList() to initialize mutex locks within the lookaside structures. It seems that in NDIS 5.0, the lookaside allocate/free routines ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(), which require the use of the per-lookaside spinlock, whereas in NDIS 5.1, the per-lookaside spinlock is deprecated. We need to support both cases. Note that I appear to be doing something wrong with ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(): they don't appear to obtain proper pointers to their arguments, so I'm probably doing something wrong in terms of their calling convention (they're declared to be FASTCALL in Widnows, and I'm not sure what that means for gcc). It happens that in my stub lookaside implementation, they don't need to do any work anyway, so for now I've hacked them to always return NULL, which avoids corrupting the stack. I need to do this right though.
2003-12-12 22:35:13 +00:00
__asm__ __volatile__ ("" : "=c" (head), "=d" (lock));
subr_ndis.c: - fix ndis_time() so that it returns a time based on the proper epoch (wacky though it may be) - implement NdisInitializeString() and NdisFreeString(), and add stub for NdisMRemoveMiniport() ntoskrnl_var.h: - add missing member to the general_lookaside struct (gl_listentry) subr_ntoskrnl.c: - Fix arguments to the interlocked push/pop routines: 'head' is an slist_header *, not an slist_entry * - Kludge up _fastcall support for the push/pop routines. The _fastcall convention is similar to _stdcall, except the first two available DWORD-sized arguments are passed in %ecx and %edx, respectively. One kludge for this __attribute__ ((regparm(3))), however this isn't entirely right, as it assumes %eax, %ecx and %edx will be used (regparm(2) assumes %eax and %edx). Another kludge is to declare the two fastcall-ed args as local register variables and explicitly assign them to %ecx and %edx, but experimentation showed that gcc would not guard %ecx and %edx against being clobbered. Thus, I came up with a 3rd kludge, which is to use some inline assembly of the form: void *arg1; void *arg2; __asm__("movl %%ecx, %%ecx" : "=c" (arg1)); __asm__("movl %%edx, %%edx" : "=d" (arg2)); This lets gcc know that we're going to reference %ecx and %edx and that it should make an effort not to let it get trampled. This wastes an instruction (movl %reg, %reg is a no-op) but insures proper behavior. It's possible there's a better way to do this though: this is the first time I've used inline assembler in this fashion. The above fixes to ntoskrnl_var.h an subr_ntoskrnl.c make lookaside lists work for the two drivers I have that use them, one of which is an NDIS 5.0 miniport and another which is 5.1.
2003-12-13 07:41:12 +00:00
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
irql = FASTCALL2(hal_lock, lock, DISPATCH_LEVEL);
first = ntoskrnl_popsl(head);
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
FASTCALL2(hal_unlock, lock, irql);
Implement some more NDIS and ntoskrnl API calls: subr_ndis.c: NdisGetCurrentSystemTime() which, according to the Microsoft documentation returns "the number of 100 nanosecond intervals since January 1, 1601." I have no idea what's so special about that epoch or why they chose 100 nanosecond ticks. I don't know the proper offset to convert nanotime() from the UNIX epoch to January 1, 1601, so for now I'm just doing the unit convertion to 100s of nanoseconds. subr_ntoskrnl.c: memcpy(), memset(), ExInterlockedPopEntrySList(), ExInterlockedPushEntrySList(). The latter two are different from InterlockedPopEntrySList() and InterlockedPushEntrySList() in that they accept a spinlock to hold while executing, whereas the non-Ex routines use a lock internal to ntoskrnl. I also modified ExInitializePagedLookasideList() and ExInitializeNPagedLookasideList() to initialize mutex locks within the lookaside structures. It seems that in NDIS 5.0, the lookaside allocate/free routines ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(), which require the use of the per-lookaside spinlock, whereas in NDIS 5.1, the per-lookaside spinlock is deprecated. We need to support both cases. Note that I appear to be doing something wrong with ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(): they don't appear to obtain proper pointers to their arguments, so I'm probably doing something wrong in terms of their calling convention (they're declared to be FASTCALL in Widnows, and I'm not sure what that means for gcc). It happens that in my stub lookaside implementation, they don't need to do any work anyway, so for now I've hacked them to always return NULL, which avoids corrupting the stack. I need to do this right though.
2003-12-12 22:35:13 +00:00
return(first);
}
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
__stdcall void
ntoskrnl_lock_dpc(/*lock*/ void)
{
kspin_lock *lock;
__asm__ __volatile__ ("" : "=c" (lock));
while (atomic_cmpset_acq_int((volatile u_int *)lock, 0, 1) == 0)
/* sit and spin */;
return;
}
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
__stdcall void
ntoskrnl_unlock_dpc(/*lock*/ void)
{
kspin_lock *lock;
__asm__ __volatile__ ("" : "=c" (lock));
atomic_store_rel_int((volatile u_int *)lock, 0);
return;
}
__stdcall static uint32_t
ntoskrnl_interlock_inc(/*addend*/ void)
{
volatile uint32_t *addend;
__asm__ __volatile__ ("" : "=c" (addend));
atomic_add_long((volatile u_long *)addend, 1);
return(*addend);
}
__stdcall static uint32_t
ntoskrnl_interlock_dec(/*addend*/ void)
{
volatile uint32_t *addend;
__asm__ __volatile__ ("" : "=c" (addend));
atomic_subtract_long((volatile u_long *)addend, 1);
return(*addend);
}
__stdcall static void
ntoskrnl_interlock_addstat(/*addend, inc*/)
{
uint64_t *addend;
uint32_t inc;
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
uint8_t irql;
__asm__ __volatile__ ("" : "=c" (addend), "=d" (inc));
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
irql = FASTCALL2(hal_lock, &ntoskrnl_global, DISPATCH_LEVEL);
*addend += inc;
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
FASTCALL2(hal_unlock, &ntoskrnl_global, irql);
return;
};
__stdcall static void
ntoskrnl_freemdl(mdl)
ndis_buffer *mdl;
{
ndis_buffer *head;
if (mdl == NULL || mdl->nb_process == NULL)
return;
head = mdl->nb_process;
if (head->nb_flags != 0x1)
return;
mdl->nb_next = head->nb_next;
head->nb_next = mdl;
Add sanity checks to the ndis_packet and ndis_buffer pool handling routines to guard against problems caused by (possibly) buggy drivers. The RealTek 8180 wireless driver calls NdisFreeBuffer() to release some of its buffers _after_ it's already called NdisFreeBufferPool() to destroy the pool to which the buffers belong. In our implementation, this error causes NdisFreeBuffer() to touch stale heap memory. If you are running a release kernel, and hence have INVARIANTS et al turned off, it turns out nothing happens. But if you're using a development kernel config with INVARIANTS on, the malloc()/free() sanity checks will scribble over the pool memory with 0xdeadc0de once it's released so that any attempts to touch it will cause a trap, and indeed this is what happens. It happens that I run 5.2-RELEASE on my laptop, so when I tested the rtl8180.sys driver, it worked fine for me, but people trying to run it with development systems checked out or cvsupped from -current would get a page fault on driver load. I can't find any reason why the NDISulator would cause the RealTek driver to do the NdisFreeBufferPool() prematurely, and the same driver obviously works with Windows -- or at least, it doesn't cause a crash: the Microsoft documentation for NdisFreeBufferPool() says that failing to return all buffers to the pool before calling NdisFreeBufferPool() causes a memory leak. I've written to my contacts at RealTek asking them to check if this is indeed a bug in their driver. In the meantime, these new sanity checks will catch this problem and issue a warning rather than causing a trap. The trick is to keep a count of outstanding buffers for each buffer pool, and if the driver tries to call NdisFreeBufferPool() while there are still buffers outstanding, we mark the pool for deletion and then defer destroying it until after the last buffer has been reclaimed.
2004-03-04 00:17:14 +00:00
/* Decrement count of busy buffers. */
head->nb_bytecount--;
/*
* If the pool has been marked for deletion and there are
* no more buffers outstanding, nuke the pool.
*/
if (head->nb_byteoffset && head->nb_bytecount == 0)
free(head, M_DEVBUF);
return;
}
__stdcall static uint32_t
ntoskrnl_sizeofmdl(vaddr, len)
void *vaddr;
size_t len;
{
uint32_t l;
l = sizeof(struct ndis_buffer) +
(sizeof(uint32_t) * SPAN_PAGES(vaddr, len));
return(l);
}
__stdcall static void
ntoskrnl_build_npaged_mdl(mdl)
ndis_buffer *mdl;
{
mdl->nb_mappedsystemva = (char *)mdl->nb_startva + mdl->nb_byteoffset;
return;
}
__stdcall static void *
ntoskrnl_mmaplockedpages(buf, accessmode)
ndis_buffer *buf;
uint8_t accessmode;
{
return(MDL_VA(buf));
}
__stdcall static void *
ntoskrnl_mmaplockedpages_cache(buf, accessmode, cachetype, vaddr,
bugcheck, prio)
ndis_buffer *buf;
uint8_t accessmode;
uint32_t cachetype;
void *vaddr;
uint32_t bugcheck;
uint32_t prio;
{
return(MDL_VA(buf));
}
__stdcall static void
ntoskrnl_munmaplockedpages(vaddr, buf)
void *vaddr;
ndis_buffer *buf;
{
return;
}
/*
* The KeInitializeSpinLock(), KefAcquireSpinLockAtDpcLevel()
* and KefReleaseSpinLockFromDpcLevel() appear to be analagous
* to splnet()/splx() in their use. We can't create a new mutex
* lock here because there is no complimentary KeFreeSpinLock()
* function. Instead, we grab a mutex from the mutex pool.
*/
__stdcall static void
ntoskrnl_init_lock(lock)
kspin_lock *lock;
{
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
*lock = 0;
return;
}
__stdcall static size_t
ntoskrnl_memcmp(s1, s2, len)
const void *s1;
const void *s2;
size_t len;
{
size_t i, total = 0;
uint8_t *m1, *m2;
m1 = __DECONST(char *, s1);
m2 = __DECONST(char *, s2);
for (i = 0; i < len; i++) {
if (m1[i] == m2[i])
total++;
}
return(total);
}
__stdcall static void
ntoskrnl_init_ansi_string(dst, src)
ndis_ansi_string *dst;
char *src;
{
ndis_ansi_string *a;
a = dst;
if (a == NULL)
return;
if (src == NULL) {
a->nas_len = a->nas_maxlen = 0;
a->nas_buf = NULL;
} else {
a->nas_buf = src;
a->nas_len = a->nas_maxlen = strlen(src);
}
return;
}
__stdcall static void
ntoskrnl_init_unicode_string(dst, src)
ndis_unicode_string *dst;
uint16_t *src;
{
ndis_unicode_string *u;
int i;
u = dst;
if (u == NULL)
return;
if (src == NULL) {
u->nus_len = u->nus_maxlen = 0;
u->nus_buf = NULL;
} else {
i = 0;
while(src[i] != 0)
i++;
u->nus_buf = src;
u->nus_len = u->nus_maxlen = i * 2;
}
return;
}
__stdcall ndis_status
ntoskrnl_unicode_to_int(ustr, base, val)
ndis_unicode_string *ustr;
uint32_t base;
uint32_t *val;
{
uint16_t *uchr;
int len, neg = 0;
char abuf[64];
char *astr;
uchr = ustr->nus_buf;
len = ustr->nus_len;
bzero(abuf, sizeof(abuf));
if ((char)((*uchr) & 0xFF) == '-') {
neg = 1;
uchr++;
len -= 2;
} else if ((char)((*uchr) & 0xFF) == '+') {
neg = 0;
uchr++;
len -= 2;
}
if (base == 0) {
if ((char)((*uchr) & 0xFF) == 'b') {
base = 2;
uchr++;
len -= 2;
} else if ((char)((*uchr) & 0xFF) == 'o') {
base = 8;
uchr++;
len -= 2;
} else if ((char)((*uchr) & 0xFF) == 'x') {
base = 16;
uchr++;
len -= 2;
} else
base = 10;
}
astr = abuf;
if (neg) {
strcpy(astr, "-");
astr++;
}
ndis_unicode_to_ascii(uchr, len, &astr);
*val = strtoul(abuf, NULL, base);
return(NDIS_STATUS_SUCCESS);
}
__stdcall static void
ntoskrnl_free_unicode_string(ustr)
ndis_unicode_string *ustr;
{
if (ustr->nus_buf == NULL)
return;
free(ustr->nus_buf, M_DEVBUF);
ustr->nus_buf = NULL;
return;
}
__stdcall static void
ntoskrnl_free_ansi_string(astr)
ndis_ansi_string *astr;
{
if (astr->nas_buf == NULL)
return;
free(astr->nas_buf, M_DEVBUF);
astr->nas_buf = NULL;
return;
}
static int
atoi(str)
const char *str;
{
return (int)strtol(str, (char **)NULL, 10);
}
static long
atol(str)
const char *str;
{
return strtol(str, (char **)NULL, 10);
}
static int
rand(void)
{
struct timeval tv;
microtime(&tv);
srandom(tv.tv_usec);
return((int)random());
}
__stdcall static uint8_t
ntoskrnl_wdmver(major, minor)
uint8_t major;
uint8_t minor;
{
if (major == WDM_MAJOR && minor == WDM_MINOR_WINXP)
return(TRUE);
return(FALSE);
}
__stdcall static ndis_status
ntoskrnl_devprop(devobj, regprop, buflen, prop, reslen)
device_object *devobj;
uint32_t regprop;
uint32_t buflen;
void *prop;
uint32_t *reslen;
{
ndis_miniport_block *block;
block = devobj->do_rsvd;
switch (regprop) {
case DEVPROP_DRIVER_KEYNAME:
ndis_ascii_to_unicode(__DECONST(char *,
device_get_nameunit(block->nmb_dev)), (uint16_t **)&prop);
*reslen = strlen(device_get_nameunit(block->nmb_dev)) * 2;
break;
default:
return(STATUS_INVALID_PARAMETER_2);
break;
}
return(STATUS_SUCCESS);
}
__stdcall static void
ntoskrnl_init_mutex(kmutex, level)
kmutant *kmutex;
uint32_t level;
{
INIT_LIST_HEAD((&kmutex->km_header.dh_waitlisthead));
kmutex->km_abandoned = FALSE;
kmutex->km_apcdisable = 1;
kmutex->km_header.dh_sigstate = TRUE;
kmutex->km_header.dh_type = EVENT_TYPE_SYNC;
kmutex->km_header.dh_size = OTYPE_MUTEX;
kmutex->km_acquirecnt = 0;
kmutex->km_ownerthread = NULL;
return;
}
__stdcall static uint32_t
ntoskrnl_release_mutex(kmutex, kwait)
kmutant *kmutex;
uint8_t kwait;
{
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_lock(&ntoskrnl_dispatchlock);
if (kmutex->km_ownerthread != curthread->td_proc) {
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_unlock(&ntoskrnl_dispatchlock);
return(STATUS_MUTANT_NOT_OWNED);
}
kmutex->km_acquirecnt--;
if (kmutex->km_acquirecnt == 0) {
kmutex->km_ownerthread = NULL;
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_unlock(&ntoskrnl_dispatchlock);
ntoskrnl_wakeup(&kmutex->km_header);
} else
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_unlock(&ntoskrnl_dispatchlock);
return(kmutex->km_acquirecnt);
}
__stdcall static uint32_t
ntoskrnl_read_mutex(kmutex)
kmutant *kmutex;
{
return(kmutex->km_header.dh_sigstate);
}
- Rewrite the timer and event API routines in subr_ndis.c so that they are actually layered on top of the KeTimer API in subr_ntoskrnl.c, just as it is in Windows. This reduces code duplication and more closely imitates the way things are done in Windows. - Modify ndis_encode_parm() to deal with the case where we have a registry key expressed as a hex value ("0x1") which is being read via NdisReadConfiguration() as an int. Previously, we tried to decode things like "0x1" with strtol() using a base of 10, which would always yield 0. This is what was causing problems with the Intel 2200BG Centrino 802.11g driver: the .inf file that comes with it has a key called RadioEnable with a value of 0x1. We incorrectly decoded this value to '0' when it was queried, hence the driver thought we wanted the radio turned off. - In if_ndis.c, most drivers don't accept NDIS_80211_AUTHMODE_AUTO, but NDIS_80211_AUTHMODE_SHARED may not be right in some cases, so for now always use NDIS_80211_AUTHMODE_OPEN. NOTE: There is still one problem with the Intel 2200BG driver: it happens that the kernel stack in Windows is larger than the kernel stack in FreeBSD. The 2200BG driver sometimes eats up more than 2 pages of stack space, which can lead to a double fault panic. For the moment, I got things to work by adding the following to my kernel config file: options KSTACK_PAGES=8 I'm pretty sure 8 is too big; I just picked this value out of a hat as a test, and it happened to work, so I left it. 4 pages might be enough. Unfortunately, I don't think you can dynamically give a thread a larger stack, so I'm not sure how to handle this short of putting a note in the man page about it and dealing with the flood of mail from people who never read man pages.
2004-03-20 23:39:43 +00:00
__stdcall void
ntoskrnl_init_event(kevent, type, state)
nt_kevent *kevent;
uint32_t type;
uint8_t state;
{
INIT_LIST_HEAD((&kevent->k_header.dh_waitlisthead));
kevent->k_header.dh_sigstate = state;
kevent->k_header.dh_type = type;
kevent->k_header.dh_size = OTYPE_EVENT;
return;
}
- Rewrite the timer and event API routines in subr_ndis.c so that they are actually layered on top of the KeTimer API in subr_ntoskrnl.c, just as it is in Windows. This reduces code duplication and more closely imitates the way things are done in Windows. - Modify ndis_encode_parm() to deal with the case where we have a registry key expressed as a hex value ("0x1") which is being read via NdisReadConfiguration() as an int. Previously, we tried to decode things like "0x1" with strtol() using a base of 10, which would always yield 0. This is what was causing problems with the Intel 2200BG Centrino 802.11g driver: the .inf file that comes with it has a key called RadioEnable with a value of 0x1. We incorrectly decoded this value to '0' when it was queried, hence the driver thought we wanted the radio turned off. - In if_ndis.c, most drivers don't accept NDIS_80211_AUTHMODE_AUTO, but NDIS_80211_AUTHMODE_SHARED may not be right in some cases, so for now always use NDIS_80211_AUTHMODE_OPEN. NOTE: There is still one problem with the Intel 2200BG driver: it happens that the kernel stack in Windows is larger than the kernel stack in FreeBSD. The 2200BG driver sometimes eats up more than 2 pages of stack space, which can lead to a double fault panic. For the moment, I got things to work by adding the following to my kernel config file: options KSTACK_PAGES=8 I'm pretty sure 8 is too big; I just picked this value out of a hat as a test, and it happened to work, so I left it. 4 pages might be enough. Unfortunately, I don't think you can dynamically give a thread a larger stack, so I'm not sure how to handle this short of putting a note in the man page about it and dealing with the flood of mail from people who never read man pages.
2004-03-20 23:39:43 +00:00
__stdcall uint32_t
ntoskrnl_reset_event(kevent)
nt_kevent *kevent;
{
uint32_t prevstate;
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_lock(&ntoskrnl_dispatchlock);
prevstate = kevent->k_header.dh_sigstate;
kevent->k_header.dh_sigstate = FALSE;
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
mtx_unlock(&ntoskrnl_dispatchlock);
return(prevstate);
}
- Rewrite the timer and event API routines in subr_ndis.c so that they are actually layered on top of the KeTimer API in subr_ntoskrnl.c, just as it is in Windows. This reduces code duplication and more closely imitates the way things are done in Windows. - Modify ndis_encode_parm() to deal with the case where we have a registry key expressed as a hex value ("0x1") which is being read via NdisReadConfiguration() as an int. Previously, we tried to decode things like "0x1" with strtol() using a base of 10, which would always yield 0. This is what was causing problems with the Intel 2200BG Centrino 802.11g driver: the .inf file that comes with it has a key called RadioEnable with a value of 0x1. We incorrectly decoded this value to '0' when it was queried, hence the driver thought we wanted the radio turned off. - In if_ndis.c, most drivers don't accept NDIS_80211_AUTHMODE_AUTO, but NDIS_80211_AUTHMODE_SHARED may not be right in some cases, so for now always use NDIS_80211_AUTHMODE_OPEN. NOTE: There is still one problem with the Intel 2200BG driver: it happens that the kernel stack in Windows is larger than the kernel stack in FreeBSD. The 2200BG driver sometimes eats up more than 2 pages of stack space, which can lead to a double fault panic. For the moment, I got things to work by adding the following to my kernel config file: options KSTACK_PAGES=8 I'm pretty sure 8 is too big; I just picked this value out of a hat as a test, and it happened to work, so I left it. 4 pages might be enough. Unfortunately, I don't think you can dynamically give a thread a larger stack, so I'm not sure how to handle this short of putting a note in the man page about it and dealing with the flood of mail from people who never read man pages.
2004-03-20 23:39:43 +00:00
__stdcall uint32_t
ntoskrnl_set_event(kevent, increment, kwait)
nt_kevent *kevent;
uint32_t increment;
uint8_t kwait;
{
uint32_t prevstate;
prevstate = kevent->k_header.dh_sigstate;
ntoskrnl_wakeup(&kevent->k_header);
return(prevstate);
}
- Rewrite the timer and event API routines in subr_ndis.c so that they are actually layered on top of the KeTimer API in subr_ntoskrnl.c, just as it is in Windows. This reduces code duplication and more closely imitates the way things are done in Windows. - Modify ndis_encode_parm() to deal with the case where we have a registry key expressed as a hex value ("0x1") which is being read via NdisReadConfiguration() as an int. Previously, we tried to decode things like "0x1" with strtol() using a base of 10, which would always yield 0. This is what was causing problems with the Intel 2200BG Centrino 802.11g driver: the .inf file that comes with it has a key called RadioEnable with a value of 0x1. We incorrectly decoded this value to '0' when it was queried, hence the driver thought we wanted the radio turned off. - In if_ndis.c, most drivers don't accept NDIS_80211_AUTHMODE_AUTO, but NDIS_80211_AUTHMODE_SHARED may not be right in some cases, so for now always use NDIS_80211_AUTHMODE_OPEN. NOTE: There is still one problem with the Intel 2200BG driver: it happens that the kernel stack in Windows is larger than the kernel stack in FreeBSD. The 2200BG driver sometimes eats up more than 2 pages of stack space, which can lead to a double fault panic. For the moment, I got things to work by adding the following to my kernel config file: options KSTACK_PAGES=8 I'm pretty sure 8 is too big; I just picked this value out of a hat as a test, and it happened to work, so I left it. 4 pages might be enough. Unfortunately, I don't think you can dynamically give a thread a larger stack, so I'm not sure how to handle this short of putting a note in the man page about it and dealing with the flood of mail from people who never read man pages.
2004-03-20 23:39:43 +00:00
__stdcall void
ntoskrnl_clear_event(kevent)
nt_kevent *kevent;
{
kevent->k_header.dh_sigstate = FALSE;
return;
}
- Rewrite the timer and event API routines in subr_ndis.c so that they are actually layered on top of the KeTimer API in subr_ntoskrnl.c, just as it is in Windows. This reduces code duplication and more closely imitates the way things are done in Windows. - Modify ndis_encode_parm() to deal with the case where we have a registry key expressed as a hex value ("0x1") which is being read via NdisReadConfiguration() as an int. Previously, we tried to decode things like "0x1" with strtol() using a base of 10, which would always yield 0. This is what was causing problems with the Intel 2200BG Centrino 802.11g driver: the .inf file that comes with it has a key called RadioEnable with a value of 0x1. We incorrectly decoded this value to '0' when it was queried, hence the driver thought we wanted the radio turned off. - In if_ndis.c, most drivers don't accept NDIS_80211_AUTHMODE_AUTO, but NDIS_80211_AUTHMODE_SHARED may not be right in some cases, so for now always use NDIS_80211_AUTHMODE_OPEN. NOTE: There is still one problem with the Intel 2200BG driver: it happens that the kernel stack in Windows is larger than the kernel stack in FreeBSD. The 2200BG driver sometimes eats up more than 2 pages of stack space, which can lead to a double fault panic. For the moment, I got things to work by adding the following to my kernel config file: options KSTACK_PAGES=8 I'm pretty sure 8 is too big; I just picked this value out of a hat as a test, and it happened to work, so I left it. 4 pages might be enough. Unfortunately, I don't think you can dynamically give a thread a larger stack, so I'm not sure how to handle this short of putting a note in the man page about it and dealing with the flood of mail from people who never read man pages.
2004-03-20 23:39:43 +00:00
__stdcall uint32_t
ntoskrnl_read_event(kevent)
nt_kevent *kevent;
{
return(kevent->k_header.dh_sigstate);
}
__stdcall static ndis_status
ntoskrnl_objref(handle, reqaccess, otype, accessmode, object, handleinfo)
ndis_handle handle;
uint32_t reqaccess;
void *otype;
uint8_t accessmode;
void **object;
void **handleinfo;
{
nt_objref *nr;
nr = malloc(sizeof(nt_objref), M_DEVBUF, M_NOWAIT|M_ZERO);
if (nr == NULL)
return(NDIS_STATUS_FAILURE);
INIT_LIST_HEAD((&nr->no_dh.dh_waitlisthead));
nr->no_obj = handle;
nr->no_dh.dh_size = OTYPE_THREAD;
TAILQ_INSERT_TAIL(&ntoskrnl_reflist, nr, link);
*object = nr;
return(NDIS_STATUS_SUCCESS);
}
__stdcall static void
ntoskrnl_objderef(/*object*/void)
{
void *object;
nt_objref *nr;
__asm__ __volatile__ ("" : "=c" (object));
nr = object;
TAILQ_REMOVE(&ntoskrnl_reflist, nr, link);
free(nr, M_DEVBUF);
return;
}
__stdcall static uint32_t
ntoskrnl_zwclose(handle)
ndis_handle handle;
{
return(STATUS_SUCCESS);
}
/*
* This is here just in case the thread returns without calling
* PsTerminateSystemThread().
*/
static void
ntoskrnl_thrfunc(arg)
void *arg;
{
thread_context *thrctx;
__stdcall uint32_t (*tfunc)(void *);
void *tctx;
uint32_t rval;
thrctx = arg;
tfunc = thrctx->tc_thrfunc;
tctx = thrctx->tc_thrctx;
free(thrctx, M_TEMP);
rval = tfunc(tctx);
ntoskrnl_thread_exit(rval);
return; /* notreached */
}
__stdcall static ndis_status
ntoskrnl_create_thread(handle, reqaccess, objattrs, phandle,
clientid, thrfunc, thrctx)
ndis_handle *handle;
uint32_t reqaccess;
void *objattrs;
ndis_handle phandle;
void *clientid;
void *thrfunc;
void *thrctx;
{
int error;
char tname[128];
thread_context *tc;
struct proc *p;
tc = malloc(sizeof(thread_context), M_TEMP, M_NOWAIT);
if (tc == NULL)
return(NDIS_STATUS_FAILURE);
tc->tc_thrctx = thrctx;
tc->tc_thrfunc = thrfunc;
sprintf(tname, "windows kthread %d", ntoskrnl_kth);
error = kthread_create(ntoskrnl_thrfunc, tc, &p,
RFHIGHPID, NDIS_KSTACK_PAGES, tname);
*handle = p;
ntoskrnl_kth++;
return(error);
}
/*
* In Windows, the exit of a thread is an event that you're allowed
* to wait on, assuming you've obtained a reference to the thread using
* ObReferenceObjectByHandle(). Unfortunately, the only way we can
* simulate this behavior is to register each thread we create in a
* reference list, and if someone holds a reference to us, we poke
* them.
*/
__stdcall static ndis_status
ntoskrnl_thread_exit(status)
ndis_status status;
{
struct nt_objref *nr;
TAILQ_FOREACH(nr, &ntoskrnl_reflist, link) {
if (nr->no_obj != curthread->td_proc)
continue;
ntoskrnl_wakeup(&nr->no_dh);
break;
}
ntoskrnl_kth--;
#if __FreeBSD_version < 502113
mtx_lock(&Giant);
#endif
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
kthread_exit(0);
return(0); /* notreached */
}
static uint32_t
ntoskrnl_dbgprint(char *fmt, ...)
{
va_list ap;
if (bootverbose) {
va_start(ap, fmt);
vprintf(fmt, ap);
}
return(STATUS_SUCCESS);
}
__stdcall static void
ntoskrnl_debugger(void)
{
kdb_enter("ntoskrnl_debugger(): breakpoint");
}
static void
ntoskrnl_timercall(arg)
void *arg;
{
ktimer *timer;
struct timeval tv;
mtx_unlock(&Giant);
timer = arg;
timer->k_header.dh_inserted = FALSE;
/*
* If this is a periodic timer, re-arm it
- Rewrite the timer and event API routines in subr_ndis.c so that they are actually layered on top of the KeTimer API in subr_ntoskrnl.c, just as it is in Windows. This reduces code duplication and more closely imitates the way things are done in Windows. - Modify ndis_encode_parm() to deal with the case where we have a registry key expressed as a hex value ("0x1") which is being read via NdisReadConfiguration() as an int. Previously, we tried to decode things like "0x1" with strtol() using a base of 10, which would always yield 0. This is what was causing problems with the Intel 2200BG Centrino 802.11g driver: the .inf file that comes with it has a key called RadioEnable with a value of 0x1. We incorrectly decoded this value to '0' when it was queried, hence the driver thought we wanted the radio turned off. - In if_ndis.c, most drivers don't accept NDIS_80211_AUTHMODE_AUTO, but NDIS_80211_AUTHMODE_SHARED may not be right in some cases, so for now always use NDIS_80211_AUTHMODE_OPEN. NOTE: There is still one problem with the Intel 2200BG driver: it happens that the kernel stack in Windows is larger than the kernel stack in FreeBSD. The 2200BG driver sometimes eats up more than 2 pages of stack space, which can lead to a double fault panic. For the moment, I got things to work by adding the following to my kernel config file: options KSTACK_PAGES=8 I'm pretty sure 8 is too big; I just picked this value out of a hat as a test, and it happened to work, so I left it. 4 pages might be enough. Unfortunately, I don't think you can dynamically give a thread a larger stack, so I'm not sure how to handle this short of putting a note in the man page about it and dealing with the flood of mail from people who never read man pages.
2004-03-20 23:39:43 +00:00
* so it will fire again. We do this before
* calling any deferred procedure calls because
* it's possible the DPC might cancel the timer,
* in which case it would be wrong for us to
* re-arm it again afterwards.
*/
if (timer->k_period) {
tv.tv_sec = 0;
tv.tv_usec = timer->k_period * 1000;
timer->k_header.dh_inserted = TRUE;
timer->k_handle =
timeout(ntoskrnl_timercall, timer, tvtohz(&tv));
}
if (timer->k_dpc != NULL)
ntoskrnl_queue_dpc(timer->k_dpc, NULL, NULL);
Fix several issues related to the KeInitializeTimer() etc... API stuff that I added recently: - When a periodic timer fires, it's automatically re-armed. We must make sure to re-arm the timer _before_ invoking any caller-supplied defered procedure call: the DPC may choose to call KeCancelTimer(), and re-arming the timer after the DPC un-does the effect of the cancel. - Fix similar issue with periodic timers in subr_ndis.c. - When calling KeSetTimer() or KeSetTimerEx(), if the timer is already pending, untimeout() it first before timeout()ing it again. - The old Atheros driver for the 5211 seems to use KeSetTimerEx() incorrectly, or at the very least in a very strange way that doesn't quite follow the Microsoft documentation. In one case, it calls KeSetTimerEx() with a duetime of 0 and a period of 5000. The Microsoft documentation says that negative duetime values are relative to the current time and positive values are absolute. But it doesn't say what's supposed to happen with positive values that less than the current time, i.e. absolute values that are in the past. Lacking any further information, I have decided that timers with positive duetimes that are in the past should fire right away (or in our case, after only 1 tick). This also takes care of the other strange usage in the Atheros driver, where the duetime is specified as 500000 and the period is 50. I think someone may have meant to use -500000 and misinterpreted the documentation. - Also modified KeWaitForSingleObject() and KeWaitForMultipleObjects() to make the same duetime adjustment, since they have the same rules regarding timeout values. - Cosmetic: change name of 'timeout' variable in KeWaitForSingleObject() and KeWaitForMultipleObjects() to 'duetime' to avoid senseless (though harmless) overlap with timeout() function name. With these fixes, I can get the 5211 card to associate properly with my adhoc net using driver AR5211.SYS version 2.4.1.6.
2004-03-10 07:43:11 +00:00
ntoskrnl_wakeup(&timer->k_header);
mtx_lock(&Giant);
return;
}
- Rewrite the timer and event API routines in subr_ndis.c so that they are actually layered on top of the KeTimer API in subr_ntoskrnl.c, just as it is in Windows. This reduces code duplication and more closely imitates the way things are done in Windows. - Modify ndis_encode_parm() to deal with the case where we have a registry key expressed as a hex value ("0x1") which is being read via NdisReadConfiguration() as an int. Previously, we tried to decode things like "0x1" with strtol() using a base of 10, which would always yield 0. This is what was causing problems with the Intel 2200BG Centrino 802.11g driver: the .inf file that comes with it has a key called RadioEnable with a value of 0x1. We incorrectly decoded this value to '0' when it was queried, hence the driver thought we wanted the radio turned off. - In if_ndis.c, most drivers don't accept NDIS_80211_AUTHMODE_AUTO, but NDIS_80211_AUTHMODE_SHARED may not be right in some cases, so for now always use NDIS_80211_AUTHMODE_OPEN. NOTE: There is still one problem with the Intel 2200BG driver: it happens that the kernel stack in Windows is larger than the kernel stack in FreeBSD. The 2200BG driver sometimes eats up more than 2 pages of stack space, which can lead to a double fault panic. For the moment, I got things to work by adding the following to my kernel config file: options KSTACK_PAGES=8 I'm pretty sure 8 is too big; I just picked this value out of a hat as a test, and it happened to work, so I left it. 4 pages might be enough. Unfortunately, I don't think you can dynamically give a thread a larger stack, so I'm not sure how to handle this short of putting a note in the man page about it and dealing with the flood of mail from people who never read man pages.
2004-03-20 23:39:43 +00:00
__stdcall void
ntoskrnl_init_timer(timer)
ktimer *timer;
{
if (timer == NULL)
return;
ntoskrnl_init_timer_ex(timer, EVENT_TYPE_NOTIFY);
return;
}
- Rewrite the timer and event API routines in subr_ndis.c so that they are actually layered on top of the KeTimer API in subr_ntoskrnl.c, just as it is in Windows. This reduces code duplication and more closely imitates the way things are done in Windows. - Modify ndis_encode_parm() to deal with the case where we have a registry key expressed as a hex value ("0x1") which is being read via NdisReadConfiguration() as an int. Previously, we tried to decode things like "0x1" with strtol() using a base of 10, which would always yield 0. This is what was causing problems with the Intel 2200BG Centrino 802.11g driver: the .inf file that comes with it has a key called RadioEnable with a value of 0x1. We incorrectly decoded this value to '0' when it was queried, hence the driver thought we wanted the radio turned off. - In if_ndis.c, most drivers don't accept NDIS_80211_AUTHMODE_AUTO, but NDIS_80211_AUTHMODE_SHARED may not be right in some cases, so for now always use NDIS_80211_AUTHMODE_OPEN. NOTE: There is still one problem with the Intel 2200BG driver: it happens that the kernel stack in Windows is larger than the kernel stack in FreeBSD. The 2200BG driver sometimes eats up more than 2 pages of stack space, which can lead to a double fault panic. For the moment, I got things to work by adding the following to my kernel config file: options KSTACK_PAGES=8 I'm pretty sure 8 is too big; I just picked this value out of a hat as a test, and it happened to work, so I left it. 4 pages might be enough. Unfortunately, I don't think you can dynamically give a thread a larger stack, so I'm not sure how to handle this short of putting a note in the man page about it and dealing with the flood of mail from people who never read man pages.
2004-03-20 23:39:43 +00:00
__stdcall void
ntoskrnl_init_timer_ex(timer, type)
ktimer *timer;
uint32_t type;
{
if (timer == NULL)
return;
INIT_LIST_HEAD((&timer->k_header.dh_waitlisthead));
timer->k_header.dh_sigstate = FALSE;
timer->k_header.dh_inserted = FALSE;
timer->k_header.dh_type = type;
timer->k_header.dh_size = OTYPE_TIMER;
callout_handle_init(&timer->k_handle);
return;
}
/*
* This is a wrapper for Windows deferred procedure calls that
* have been placed on an NDIS thread work queue. We need it
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
* since the DPC could be a _stdcall function. Also, as far as
* I can tell, defered procedure calls must run at DISPATCH_LEVEL.
*/
static void
ntoskrnl_run_dpc(arg)
void *arg;
{
__stdcall kdpc_func dpcfunc;
kdpc *dpc;
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
uint8_t irql;
dpc = arg;
dpcfunc = (kdpc_func)dpc->k_deferedfunc;
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL);
dpcfunc(dpc, dpc->k_deferredctx, dpc->k_sysarg1, dpc->k_sysarg2);
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it. FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool. Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway. Overview of the changes: - Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority. - Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks. - Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat. - Remove ndis_mtxpool and all references to it. We don't need it anymore. - Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows. - Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before. - Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c. - Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.) - Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL. - In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway. - Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode. - Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation. I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
2004-04-14 07:48:03 +00:00
FASTCALL1(hal_lower_irql, irql);
return;
}
- Rewrite the timer and event API routines in subr_ndis.c so that they are actually layered on top of the KeTimer API in subr_ntoskrnl.c, just as it is in Windows. This reduces code duplication and more closely imitates the way things are done in Windows. - Modify ndis_encode_parm() to deal with the case where we have a registry key expressed as a hex value ("0x1") which is being read via NdisReadConfiguration() as an int. Previously, we tried to decode things like "0x1" with strtol() using a base of 10, which would always yield 0. This is what was causing problems with the Intel 2200BG Centrino 802.11g driver: the .inf file that comes with it has a key called RadioEnable with a value of 0x1. We incorrectly decoded this value to '0' when it was queried, hence the driver thought we wanted the radio turned off. - In if_ndis.c, most drivers don't accept NDIS_80211_AUTHMODE_AUTO, but NDIS_80211_AUTHMODE_SHARED may not be right in some cases, so for now always use NDIS_80211_AUTHMODE_OPEN. NOTE: There is still one problem with the Intel 2200BG driver: it happens that the kernel stack in Windows is larger than the kernel stack in FreeBSD. The 2200BG driver sometimes eats up more than 2 pages of stack space, which can lead to a double fault panic. For the moment, I got things to work by adding the following to my kernel config file: options KSTACK_PAGES=8 I'm pretty sure 8 is too big; I just picked this value out of a hat as a test, and it happened to work, so I left it. 4 pages might be enough. Unfortunately, I don't think you can dynamically give a thread a larger stack, so I'm not sure how to handle this short of putting a note in the man page about it and dealing with the flood of mail from people who never read man pages.
2004-03-20 23:39:43 +00:00
__stdcall void
ntoskrnl_init_dpc(dpc, dpcfunc, dpcctx)
kdpc *dpc;
void *dpcfunc;
void *dpcctx;
{
if (dpc == NULL)
return;
dpc->k_deferedfunc = dpcfunc;
dpc->k_deferredctx = dpcctx;
return;
}
__stdcall uint8_t
ntoskrnl_queue_dpc(dpc, sysarg1, sysarg2)
kdpc *dpc;
void *sysarg1;
void *sysarg2;
{
dpc->k_sysarg1 = sysarg1;
dpc->k_sysarg2 = sysarg2;
if (ndis_sched(ntoskrnl_run_dpc, dpc, NDIS_SWI))
return(FALSE);
return(TRUE);
}
__stdcall uint8_t
ntoskrnl_dequeue_dpc(dpc)
kdpc *dpc;
{
if (ndis_unsched(ntoskrnl_run_dpc, dpc, NDIS_SWI))
return(FALSE);
return(TRUE);
}
- Rewrite the timer and event API routines in subr_ndis.c so that they are actually layered on top of the KeTimer API in subr_ntoskrnl.c, just as it is in Windows. This reduces code duplication and more closely imitates the way things are done in Windows. - Modify ndis_encode_parm() to deal with the case where we have a registry key expressed as a hex value ("0x1") which is being read via NdisReadConfiguration() as an int. Previously, we tried to decode things like "0x1" with strtol() using a base of 10, which would always yield 0. This is what was causing problems with the Intel 2200BG Centrino 802.11g driver: the .inf file that comes with it has a key called RadioEnable with a value of 0x1. We incorrectly decoded this value to '0' when it was queried, hence the driver thought we wanted the radio turned off. - In if_ndis.c, most drivers don't accept NDIS_80211_AUTHMODE_AUTO, but NDIS_80211_AUTHMODE_SHARED may not be right in some cases, so for now always use NDIS_80211_AUTHMODE_OPEN. NOTE: There is still one problem with the Intel 2200BG driver: it happens that the kernel stack in Windows is larger than the kernel stack in FreeBSD. The 2200BG driver sometimes eats up more than 2 pages of stack space, which can lead to a double fault panic. For the moment, I got things to work by adding the following to my kernel config file: options KSTACK_PAGES=8 I'm pretty sure 8 is too big; I just picked this value out of a hat as a test, and it happened to work, so I left it. 4 pages might be enough. Unfortunately, I don't think you can dynamically give a thread a larger stack, so I'm not sure how to handle this short of putting a note in the man page about it and dealing with the flood of mail from people who never read man pages.
2004-03-20 23:39:43 +00:00
__stdcall uint8_t
ntoskrnl_set_timer_ex(timer, duetime, period, dpc)
ktimer *timer;
int64_t duetime;
uint32_t period;
kdpc *dpc;
{
struct timeval tv;
uint64_t curtime;
uint8_t pending;
if (timer == NULL)
return(FALSE);
if (timer->k_header.dh_inserted == TRUE) {
untimeout(ntoskrnl_timercall, timer, timer->k_handle);
timer->k_header.dh_inserted = FALSE;
pending = TRUE;
Fix several issues related to the KeInitializeTimer() etc... API stuff that I added recently: - When a periodic timer fires, it's automatically re-armed. We must make sure to re-arm the timer _before_ invoking any caller-supplied defered procedure call: the DPC may choose to call KeCancelTimer(), and re-arming the timer after the DPC un-does the effect of the cancel. - Fix similar issue with periodic timers in subr_ndis.c. - When calling KeSetTimer() or KeSetTimerEx(), if the timer is already pending, untimeout() it first before timeout()ing it again. - The old Atheros driver for the 5211 seems to use KeSetTimerEx() incorrectly, or at the very least in a very strange way that doesn't quite follow the Microsoft documentation. In one case, it calls KeSetTimerEx() with a duetime of 0 and a period of 5000. The Microsoft documentation says that negative duetime values are relative to the current time and positive values are absolute. But it doesn't say what's supposed to happen with positive values that less than the current time, i.e. absolute values that are in the past. Lacking any further information, I have decided that timers with positive duetimes that are in the past should fire right away (or in our case, after only 1 tick). This also takes care of the other strange usage in the Atheros driver, where the duetime is specified as 500000 and the period is 50. I think someone may have meant to use -500000 and misinterpreted the documentation. - Also modified KeWaitForSingleObject() and KeWaitForMultipleObjects() to make the same duetime adjustment, since they have the same rules regarding timeout values. - Cosmetic: change name of 'timeout' variable in KeWaitForSingleObject() and KeWaitForMultipleObjects() to 'duetime' to avoid senseless (though harmless) overlap with timeout() function name. With these fixes, I can get the 5211 card to associate properly with my adhoc net using driver AR5211.SYS version 2.4.1.6.
2004-03-10 07:43:11 +00:00
} else
pending = FALSE;
timer->k_duetime = duetime;
timer->k_period = period;
timer->k_header.dh_sigstate = FALSE;
timer->k_dpc = dpc;
if (duetime < 0) {
Fix several issues related to the KeInitializeTimer() etc... API stuff that I added recently: - When a periodic timer fires, it's automatically re-armed. We must make sure to re-arm the timer _before_ invoking any caller-supplied defered procedure call: the DPC may choose to call KeCancelTimer(), and re-arming the timer after the DPC un-does the effect of the cancel. - Fix similar issue with periodic timers in subr_ndis.c. - When calling KeSetTimer() or KeSetTimerEx(), if the timer is already pending, untimeout() it first before timeout()ing it again. - The old Atheros driver for the 5211 seems to use KeSetTimerEx() incorrectly, or at the very least in a very strange way that doesn't quite follow the Microsoft documentation. In one case, it calls KeSetTimerEx() with a duetime of 0 and a period of 5000. The Microsoft documentation says that negative duetime values are relative to the current time and positive values are absolute. But it doesn't say what's supposed to happen with positive values that less than the current time, i.e. absolute values that are in the past. Lacking any further information, I have decided that timers with positive duetimes that are in the past should fire right away (or in our case, after only 1 tick). This also takes care of the other strange usage in the Atheros driver, where the duetime is specified as 500000 and the period is 50. I think someone may have meant to use -500000 and misinterpreted the documentation. - Also modified KeWaitForSingleObject() and KeWaitForMultipleObjects() to make the same duetime adjustment, since they have the same rules regarding timeout values. - Cosmetic: change name of 'timeout' variable in KeWaitForSingleObject() and KeWaitForMultipleObjects() to 'duetime' to avoid senseless (though harmless) overlap with timeout() function name. With these fixes, I can get the 5211 card to associate properly with my adhoc net using driver AR5211.SYS version 2.4.1.6.
2004-03-10 07:43:11 +00:00
tv.tv_sec = - (duetime) / 10000000;
tv.tv_usec = (- (duetime) / 10) -
(tv.tv_sec * 1000000);
} else {
ntoskrnl_time(&curtime);
Fix several issues related to the KeInitializeTimer() etc... API stuff that I added recently: - When a periodic timer fires, it's automatically re-armed. We must make sure to re-arm the timer _before_ invoking any caller-supplied defered procedure call: the DPC may choose to call KeCancelTimer(), and re-arming the timer after the DPC un-does the effect of the cancel. - Fix similar issue with periodic timers in subr_ndis.c. - When calling KeSetTimer() or KeSetTimerEx(), if the timer is already pending, untimeout() it first before timeout()ing it again. - The old Atheros driver for the 5211 seems to use KeSetTimerEx() incorrectly, or at the very least in a very strange way that doesn't quite follow the Microsoft documentation. In one case, it calls KeSetTimerEx() with a duetime of 0 and a period of 5000. The Microsoft documentation says that negative duetime values are relative to the current time and positive values are absolute. But it doesn't say what's supposed to happen with positive values that less than the current time, i.e. absolute values that are in the past. Lacking any further information, I have decided that timers with positive duetimes that are in the past should fire right away (or in our case, after only 1 tick). This also takes care of the other strange usage in the Atheros driver, where the duetime is specified as 500000 and the period is 50. I think someone may have meant to use -500000 and misinterpreted the documentation. - Also modified KeWaitForSingleObject() and KeWaitForMultipleObjects() to make the same duetime adjustment, since they have the same rules regarding timeout values. - Cosmetic: change name of 'timeout' variable in KeWaitForSingleObject() and KeWaitForMultipleObjects() to 'duetime' to avoid senseless (though harmless) overlap with timeout() function name. With these fixes, I can get the 5211 card to associate properly with my adhoc net using driver AR5211.SYS version 2.4.1.6.
2004-03-10 07:43:11 +00:00
if (duetime < curtime)
tv.tv_sec = tv.tv_usec = 0;
else {
tv.tv_sec = ((duetime) - curtime) / 10000000;
tv.tv_usec = ((duetime) - curtime) / 10 -
(tv.tv_sec * 1000000);
}
}
timer->k_header.dh_inserted = TRUE;
timer->k_handle = timeout(ntoskrnl_timercall, timer, tvtohz(&tv));
return(pending);
}
- Rewrite the timer and event API routines in subr_ndis.c so that they are actually layered on top of the KeTimer API in subr_ntoskrnl.c, just as it is in Windows. This reduces code duplication and more closely imitates the way things are done in Windows. - Modify ndis_encode_parm() to deal with the case where we have a registry key expressed as a hex value ("0x1") which is being read via NdisReadConfiguration() as an int. Previously, we tried to decode things like "0x1" with strtol() using a base of 10, which would always yield 0. This is what was causing problems with the Intel 2200BG Centrino 802.11g driver: the .inf file that comes with it has a key called RadioEnable with a value of 0x1. We incorrectly decoded this value to '0' when it was queried, hence the driver thought we wanted the radio turned off. - In if_ndis.c, most drivers don't accept NDIS_80211_AUTHMODE_AUTO, but NDIS_80211_AUTHMODE_SHARED may not be right in some cases, so for now always use NDIS_80211_AUTHMODE_OPEN. NOTE: There is still one problem with the Intel 2200BG driver: it happens that the kernel stack in Windows is larger than the kernel stack in FreeBSD. The 2200BG driver sometimes eats up more than 2 pages of stack space, which can lead to a double fault panic. For the moment, I got things to work by adding the following to my kernel config file: options KSTACK_PAGES=8 I'm pretty sure 8 is too big; I just picked this value out of a hat as a test, and it happened to work, so I left it. 4 pages might be enough. Unfortunately, I don't think you can dynamically give a thread a larger stack, so I'm not sure how to handle this short of putting a note in the man page about it and dealing with the flood of mail from people who never read man pages.
2004-03-20 23:39:43 +00:00
__stdcall uint8_t
ntoskrnl_set_timer(timer, duetime, dpc)
ktimer *timer;
int64_t duetime;
kdpc *dpc;
{
return (ntoskrnl_set_timer_ex(timer, duetime, 0, dpc));
}
- Rewrite the timer and event API routines in subr_ndis.c so that they are actually layered on top of the KeTimer API in subr_ntoskrnl.c, just as it is in Windows. This reduces code duplication and more closely imitates the way things are done in Windows. - Modify ndis_encode_parm() to deal with the case where we have a registry key expressed as a hex value ("0x1") which is being read via NdisReadConfiguration() as an int. Previously, we tried to decode things like "0x1" with strtol() using a base of 10, which would always yield 0. This is what was causing problems with the Intel 2200BG Centrino 802.11g driver: the .inf file that comes with it has a key called RadioEnable with a value of 0x1. We incorrectly decoded this value to '0' when it was queried, hence the driver thought we wanted the radio turned off. - In if_ndis.c, most drivers don't accept NDIS_80211_AUTHMODE_AUTO, but NDIS_80211_AUTHMODE_SHARED may not be right in some cases, so for now always use NDIS_80211_AUTHMODE_OPEN. NOTE: There is still one problem with the Intel 2200BG driver: it happens that the kernel stack in Windows is larger than the kernel stack in FreeBSD. The 2200BG driver sometimes eats up more than 2 pages of stack space, which can lead to a double fault panic. For the moment, I got things to work by adding the following to my kernel config file: options KSTACK_PAGES=8 I'm pretty sure 8 is too big; I just picked this value out of a hat as a test, and it happened to work, so I left it. 4 pages might be enough. Unfortunately, I don't think you can dynamically give a thread a larger stack, so I'm not sure how to handle this short of putting a note in the man page about it and dealing with the flood of mail from people who never read man pages.
2004-03-20 23:39:43 +00:00
__stdcall uint8_t
ntoskrnl_cancel_timer(timer)
ktimer *timer;
{
uint8_t pending;
if (timer == NULL)
return(FALSE);
if (timer->k_header.dh_inserted == TRUE) {
untimeout(ntoskrnl_timercall, timer, timer->k_handle);
if (timer->k_dpc != NULL)
ntoskrnl_dequeue_dpc(timer->k_dpc);
pending = TRUE;
} else
pending = FALSE;
return(pending);
}
- Rewrite the timer and event API routines in subr_ndis.c so that they are actually layered on top of the KeTimer API in subr_ntoskrnl.c, just as it is in Windows. This reduces code duplication and more closely imitates the way things are done in Windows. - Modify ndis_encode_parm() to deal with the case where we have a registry key expressed as a hex value ("0x1") which is being read via NdisReadConfiguration() as an int. Previously, we tried to decode things like "0x1" with strtol() using a base of 10, which would always yield 0. This is what was causing problems with the Intel 2200BG Centrino 802.11g driver: the .inf file that comes with it has a key called RadioEnable with a value of 0x1. We incorrectly decoded this value to '0' when it was queried, hence the driver thought we wanted the radio turned off. - In if_ndis.c, most drivers don't accept NDIS_80211_AUTHMODE_AUTO, but NDIS_80211_AUTHMODE_SHARED may not be right in some cases, so for now always use NDIS_80211_AUTHMODE_OPEN. NOTE: There is still one problem with the Intel 2200BG driver: it happens that the kernel stack in Windows is larger than the kernel stack in FreeBSD. The 2200BG driver sometimes eats up more than 2 pages of stack space, which can lead to a double fault panic. For the moment, I got things to work by adding the following to my kernel config file: options KSTACK_PAGES=8 I'm pretty sure 8 is too big; I just picked this value out of a hat as a test, and it happened to work, so I left it. 4 pages might be enough. Unfortunately, I don't think you can dynamically give a thread a larger stack, so I'm not sure how to handle this short of putting a note in the man page about it and dealing with the flood of mail from people who never read man pages.
2004-03-20 23:39:43 +00:00
__stdcall uint8_t
ntoskrnl_read_timer(timer)
ktimer *timer;
{
return(timer->k_header.dh_sigstate);
}
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
__stdcall static void
dummy()
{
printf ("ntoskrnl dummy called...\n");
return;
}
image_patch_table ntoskrnl_functbl[] = {
{ "RtlCompareMemory", (FUNC)ntoskrnl_memcmp },
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
{ "RtlEqualUnicodeString", (FUNC)ntoskrnl_unicode_equal },
{ "RtlCopyUnicodeString", (FUNC)ntoskrnl_unicode_copy },
{ "RtlUnicodeStringToAnsiString", (FUNC)ntoskrnl_unicode_to_ansi },
{ "RtlAnsiStringToUnicodeString", (FUNC)ntoskrnl_ansi_to_unicode },
{ "RtlInitAnsiString", (FUNC)ntoskrnl_init_ansi_string },
{ "RtlInitUnicodeString", (FUNC)ntoskrnl_init_unicode_string },
{ "RtlFreeAnsiString", (FUNC)ntoskrnl_free_ansi_string },
{ "RtlFreeUnicodeString", (FUNC)ntoskrnl_free_unicode_string },
{ "RtlUnicodeStringToInteger", (FUNC)ntoskrnl_unicode_to_int },
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
{ "sprintf", (FUNC)sprintf },
{ "vsprintf", (FUNC)vsprintf },
{ "_snprintf", (FUNC)snprintf },
{ "_vsnprintf", (FUNC)vsnprintf },
{ "DbgPrint", (FUNC)ntoskrnl_dbgprint },
{ "DbgBreakPoint", (FUNC)ntoskrnl_debugger },
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
{ "strncmp", (FUNC)strncmp },
{ "strcmp", (FUNC)strcmp },
{ "strncpy", (FUNC)strncpy },
{ "strcpy", (FUNC)strcpy },
Implement some more NDIS and ntoskrnl API calls: subr_ndis.c: NdisGetCurrentSystemTime() which, according to the Microsoft documentation returns "the number of 100 nanosecond intervals since January 1, 1601." I have no idea what's so special about that epoch or why they chose 100 nanosecond ticks. I don't know the proper offset to convert nanotime() from the UNIX epoch to January 1, 1601, so for now I'm just doing the unit convertion to 100s of nanoseconds. subr_ntoskrnl.c: memcpy(), memset(), ExInterlockedPopEntrySList(), ExInterlockedPushEntrySList(). The latter two are different from InterlockedPopEntrySList() and InterlockedPushEntrySList() in that they accept a spinlock to hold while executing, whereas the non-Ex routines use a lock internal to ntoskrnl. I also modified ExInitializePagedLookasideList() and ExInitializeNPagedLookasideList() to initialize mutex locks within the lookaside structures. It seems that in NDIS 5.0, the lookaside allocate/free routines ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(), which require the use of the per-lookaside spinlock, whereas in NDIS 5.1, the per-lookaside spinlock is deprecated. We need to support both cases. Note that I appear to be doing something wrong with ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(): they don't appear to obtain proper pointers to their arguments, so I'm probably doing something wrong in terms of their calling convention (they're declared to be FASTCALL in Widnows, and I'm not sure what that means for gcc). It happens that in my stub lookaside implementation, they don't need to do any work anyway, so for now I've hacked them to always return NULL, which avoids corrupting the stack. I need to do this right though.
2003-12-12 22:35:13 +00:00
{ "strlen", (FUNC)strlen },
{ "memcpy", (FUNC)memcpy },
{ "memmove", (FUNC)memcpy },
Implement some more NDIS and ntoskrnl API calls: subr_ndis.c: NdisGetCurrentSystemTime() which, according to the Microsoft documentation returns "the number of 100 nanosecond intervals since January 1, 1601." I have no idea what's so special about that epoch or why they chose 100 nanosecond ticks. I don't know the proper offset to convert nanotime() from the UNIX epoch to January 1, 1601, so for now I'm just doing the unit convertion to 100s of nanoseconds. subr_ntoskrnl.c: memcpy(), memset(), ExInterlockedPopEntrySList(), ExInterlockedPushEntrySList(). The latter two are different from InterlockedPopEntrySList() and InterlockedPushEntrySList() in that they accept a spinlock to hold while executing, whereas the non-Ex routines use a lock internal to ntoskrnl. I also modified ExInitializePagedLookasideList() and ExInitializeNPagedLookasideList() to initialize mutex locks within the lookaside structures. It seems that in NDIS 5.0, the lookaside allocate/free routines ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(), which require the use of the per-lookaside spinlock, whereas in NDIS 5.1, the per-lookaside spinlock is deprecated. We need to support both cases. Note that I appear to be doing something wrong with ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(): they don't appear to obtain proper pointers to their arguments, so I'm probably doing something wrong in terms of their calling convention (they're declared to be FASTCALL in Widnows, and I'm not sure what that means for gcc). It happens that in my stub lookaside implementation, they don't need to do any work anyway, so for now I've hacked them to always return NULL, which avoids corrupting the stack. I need to do this right though.
2003-12-12 22:35:13 +00:00
{ "memset", (FUNC)memset },
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
{ "IofCallDriver", (FUNC)ntoskrnl_iofcalldriver },
{ "IofCompleteRequest", (FUNC)ntoskrnl_iofcompletereq },
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
{ "IoBuildSynchronousFsdRequest", (FUNC)ntoskrnl_iobuildsynchfsdreq },
{ "KeWaitForSingleObject", (FUNC)ntoskrnl_waitforobj },
{ "KeWaitForMultipleObjects", (FUNC)ntoskrnl_waitforobjs },
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
{ "_allmul", (FUNC)_allmul },
{ "_alldiv", (FUNC)_alldiv },
{ "_allrem", (FUNC)_allrem },
{ "_allshr", (FUNC)_allshr },
{ "_allshl", (FUNC)_allshl },
{ "_aullmul", (FUNC)_aullmul },
{ "_aulldiv", (FUNC)_aulldiv },
{ "_aullrem", (FUNC)_aullrem },
{ "_aullshr", (FUNC)_aullshr },
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
{ "_aullshl", (FUNC)_aullshl },
{ "atoi", (FUNC)atoi },
{ "atol", (FUNC)atol },
{ "rand", (FUNC)rand },
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
{ "WRITE_REGISTER_USHORT", (FUNC)ntoskrnl_writereg_ushort },
{ "READ_REGISTER_USHORT", (FUNC)ntoskrnl_readreg_ushort },
{ "WRITE_REGISTER_ULONG", (FUNC)ntoskrnl_writereg_ulong },
{ "READ_REGISTER_ULONG", (FUNC)ntoskrnl_readreg_ulong },
{ "READ_REGISTER_UCHAR", (FUNC)ntoskrnl_readreg_uchar },
{ "WRITE_REGISTER_UCHAR", (FUNC)ntoskrnl_writereg_uchar },
{ "ExInitializePagedLookasideList", (FUNC)ntoskrnl_init_lookaside },
{ "ExDeletePagedLookasideList", (FUNC)ntoskrnl_delete_lookaside },
{ "ExInitializeNPagedLookasideList", (FUNC)ntoskrnl_init_nplookaside },
{ "ExDeleteNPagedLookasideList", (FUNC)ntoskrnl_delete_nplookaside },
{ "InterlockedPopEntrySList", (FUNC)ntoskrnl_pop_slist },
{ "InterlockedPushEntrySList", (FUNC)ntoskrnl_push_slist },
Implement some more NDIS and ntoskrnl API calls: subr_ndis.c: NdisGetCurrentSystemTime() which, according to the Microsoft documentation returns "the number of 100 nanosecond intervals since January 1, 1601." I have no idea what's so special about that epoch or why they chose 100 nanosecond ticks. I don't know the proper offset to convert nanotime() from the UNIX epoch to January 1, 1601, so for now I'm just doing the unit convertion to 100s of nanoseconds. subr_ntoskrnl.c: memcpy(), memset(), ExInterlockedPopEntrySList(), ExInterlockedPushEntrySList(). The latter two are different from InterlockedPopEntrySList() and InterlockedPushEntrySList() in that they accept a spinlock to hold while executing, whereas the non-Ex routines use a lock internal to ntoskrnl. I also modified ExInitializePagedLookasideList() and ExInitializeNPagedLookasideList() to initialize mutex locks within the lookaside structures. It seems that in NDIS 5.0, the lookaside allocate/free routines ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(), which require the use of the per-lookaside spinlock, whereas in NDIS 5.1, the per-lookaside spinlock is deprecated. We need to support both cases. Note that I appear to be doing something wrong with ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(): they don't appear to obtain proper pointers to their arguments, so I'm probably doing something wrong in terms of their calling convention (they're declared to be FASTCALL in Widnows, and I'm not sure what that means for gcc). It happens that in my stub lookaside implementation, they don't need to do any work anyway, so for now I've hacked them to always return NULL, which avoids corrupting the stack. I need to do this right though.
2003-12-12 22:35:13 +00:00
{ "ExInterlockedPopEntrySList", (FUNC)ntoskrnl_pop_slist_ex },
{ "ExInterlockedPushEntrySList",(FUNC)ntoskrnl_push_slist_ex },
{ "KefAcquireSpinLockAtDpcLevel", (FUNC)ntoskrnl_lock_dpc },
{ "KefReleaseSpinLockFromDpcLevel", (FUNC)ntoskrnl_unlock_dpc },
{ "InterlockedIncrement", (FUNC)ntoskrnl_interlock_inc },
{ "InterlockedDecrement", (FUNC)ntoskrnl_interlock_dec },
{ "ExInterlockedAddLargeStatistic",
(FUNC)ntoskrnl_interlock_addstat },
{ "IoFreeMdl", (FUNC)ntoskrnl_freemdl },
{ "MmSizeOfMdl", (FUNC)ntoskrnl_sizeofmdl },
{ "MmMapLockedPages", (FUNC)ntoskrnl_mmaplockedpages },
{ "MmMapLockedPagesSpecifyCache",
(FUNC)ntoskrnl_mmaplockedpages_cache },
{ "MmUnmapLockedPages", (FUNC)ntoskrnl_munmaplockedpages },
{ "MmBuildMdlForNonPagedPool", (FUNC)ntoskrnl_build_npaged_mdl },
{ "KeInitializeSpinLock", (FUNC)ntoskrnl_init_lock },
{ "IoIsWdmVersionAvailable", (FUNC)ntoskrnl_wdmver },
{ "IoGetDeviceProperty", (FUNC)ntoskrnl_devprop },
{ "KeInitializeMutex", (FUNC)ntoskrnl_init_mutex },
{ "KeReleaseMutex", (FUNC)ntoskrnl_release_mutex },
{ "KeReadStateMutex", (FUNC)ntoskrnl_read_mutex },
{ "KeInitializeEvent", (FUNC)ntoskrnl_init_event },
{ "KeSetEvent", (FUNC)ntoskrnl_set_event },
{ "KeResetEvent", (FUNC)ntoskrnl_reset_event },
{ "KeClearEvent", (FUNC)ntoskrnl_clear_event },
{ "KeReadStateEvent", (FUNC)ntoskrnl_read_event },
{ "KeInitializeTimer", (FUNC)ntoskrnl_init_timer },
{ "KeInitializeTimerEx", (FUNC)ntoskrnl_init_timer_ex },
{ "KeSetTimer", (FUNC)ntoskrnl_set_timer },
{ "KeSetTimerEx", (FUNC)ntoskrnl_set_timer_ex },
{ "KeCancelTimer", (FUNC)ntoskrnl_cancel_timer },
{ "KeReadStateTimer", (FUNC)ntoskrnl_read_timer },
{ "KeInitializeDpc", (FUNC)ntoskrnl_init_dpc },
{ "KeInsertQueueDpc", (FUNC)ntoskrnl_queue_dpc },
{ "KeRemoveQueueDpc", (FUNC)ntoskrnl_dequeue_dpc },
{ "ObReferenceObjectByHandle", (FUNC)ntoskrnl_objref },
{ "ObfDereferenceObject", (FUNC)ntoskrnl_objderef },
{ "ZwClose", (FUNC)ntoskrnl_zwclose },
{ "PsCreateSystemThread", (FUNC)ntoskrnl_create_thread },
{ "PsTerminateSystemThread", (FUNC)ntoskrnl_thread_exit },
Commit the first cut of Project Evil, also known as the NDISulator. Yes, it's what you think it is. Yes, you should run away now. This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts: sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines. sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module. usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.) ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point. This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this: # cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them. An example usage of the Broadcom wireless driver would be: # sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up Things to be done: - get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
2003-12-11 22:34:37 +00:00
/*
* This last entry is a catch-all for any function we haven't
* implemented yet. The PE import list patching routine will
* use it for any function that doesn't have an explicit match
* in this table.
*/
{ NULL, (FUNC)dummy },
/* End of list. */
{ NULL, NULL },
};