History log of /freebsd-head/sys/compat/ndis/subr_ntoskrnl.c
Revision Date Author Comments
6265a56fda2455ca5973c47b3d0d702ed6d409ec 01-Sep-2020 mjg <mjg@FreeBSD.org> compat: clean up empty lines in .c and .h files
ad355b0a9dbd6a8aabe7c081a731d24904a0f2c1 26-Feb-2020 kaktus <kaktus@FreeBSD.org> Mark more nodes as CTLFLAG_MPSAFE or CTLFLAG_NEEDGIANT (17 of many)

r357614 added CTLFLAG_NEEDGIANT to make it easier to find nodes that are
still not MPSAFE (or already are but aren’t properly marked).
Use it in preparation for a general review of all nodes.

This is non-functional change that adds annotations to SYSCTL_NODE and
SYSCTL_PROC nodes using one of the soon-to-be-required flags.

Mark all obvious cases as MPSAFE. All entries that haven't been marked
as MPSAFE before are by default marked as NEEDGIANT

Approved by: kib (mentor, blanket)
Commented by: kib, gallatin, melifaro
Differential Revision: https://reviews.freebsd.org/D23718
a212d0b2e84d9c6aac527a5d831a60dac57faa14 26-Dec-2019 cem <cem@FreeBSD.org> random(9): Deprecate random(9), remove meaningless srandom(9)

srandom(9) is meaningless on SMP systems or any system with, say,
interrupts. One could never rely on random(9) to produce a reproducible
sequence of outputs on the basis of a specific srandom() seed because the
global state was shared by all kernel contexts. As such, removing it is
literally indistinguishable to random(9) consumers (as compared with
retaining it).

Mark random(9) as deprecated and slated for quick removal. This is not to
say we intend to remove all fast, non-cryptographic PRNG(s) in the kernel.
It/they just won't be random(9), as it exists today, in either name or

Before random(9) is removed, a replacement will be provided and in-tree
consumers will be converted.

Note that despite the name, the random(9) interface does not bear any
resemblance to random(3). Instead, it is the same crummy 1988 Park-Miller
LCG used in libc rand(3).
71b5b012c470799caab3128c9b365585d08aa7e2 20-Aug-2018 alc <alc@FreeBSD.org> Eliminate kmem_alloc_contig()'s unused arena parameter.

Reviewed by: hselasky, kib, markj
Discussed with: jeff
Differential Revision: https://reviews.freebsd.org/D16799
9da7bdde061c43b87cf9bb2852984b78e292b1e6 18-Nov-2017 pfg <pfg@FreeBSD.org> spdx: initial adoption of licensing ID tags.

The Software Package Data Exchange (SPDX) group provides a specification
to make it easier for automated tools to detect and summarize well known
opensource licenses. We are gradually adopting the specification, noting
that the tags are considered only advisory and do not, in any way,
superceed or replace the license texts.

Special thanks to Wind River for providing access to "The Duke of
Highlander" tool: an older (2014) run over FreeBSD tree was useful as a
starting point.

Initially, only tag files that use BSD 4-Clause "Original" license.

RelNotes: yes
Differential Revision: https://reviews.freebsd.org/D13133
0ec6462c7bfa7a6a0dfbe038697d711d955e2ebe 04-Jun-2016 pfg <pfg@FreeBSD.org> MFC r300376:
ndis(4): Better mimic the behavior of rand() on Windows.

In ndis(4) we expose a rand() function that was constantly reseeding
with a time depending function every time it was called. This
essentially broke the reasoning behind seeding, and rendered srand()
a no-op.

Keep it simple, just use random() and srandom() as it's meant to work.
It would have been tempting to just go for arc4random() but we
want to mimic Microsoft, and we don't need crypto-grade randomness

PR: 209616
00d578928eca75be320b36d37543a7e2a4f9fbdb 27-May-2016 grehan <grehan@FreeBSD.org> Create branch for bhyve graphics import.
af76274c5eaba8afc08bdf1d0ee9ba18dcd01bd9 22-May-2016 pfg <pfg@FreeBSD.org> ndis(4): Undo unneeded workarounds in ndis' rand().

- Revert the change for seed(0) in r300384. I misunderstood the standard
and while our random() implementation in libkern may be improved, it
handles the seed(0) case fine.

Pointed out by: bde, ache
f0a486d17186001c93c08d3a3ad8b62498080196 22-May-2016 pfg <pfg@FreeBSD.org> ndis(4): adjustments for our random() specific implementation.

- Revert r300377: The implementation claims to return a value
within the range. [1]
- Adjust the value for the case of a zero seed, whihc according
to standards should be equivalent to a seed of value 1.

Pointed out by: cem
334d424627d50cc4cc73e73954534e23a1f91168 21-May-2016 pfg <pfg@FreeBSD.org> ndis(4): Avoid overflow.

This is a long standing problem: our random() function returns an
unsigned integer but the rand provided by ndis(4) returns an int.
Scale it down.

MFC after: 2 weeks
e0f6fb692ee6ec627ff147b11b0c3840d5446b97 21-May-2016 pfg <pfg@FreeBSD.org> ndis(4): Better mimic the behavior of rand() on Windows.

In ndis(4) we expose a rand() function that was constantly reseeding
with a time depending function every time it was called. This
essentially broke the reasoning behind seeding, and rendered srand()
a no-op.

Keep it simple, just use random() and srandom() as it's meant to work.
It would have been tempting to just go for arc4random() but we
want to mimic Microsoft, and we don't need crypto-grade randomness

PR: 209616
MFC after: 2 weeks
2824fbf0a84a4fe891aa1320d3850555aa30aa4c 30-Apr-2016 pfg <pfg@FreeBSD.org> ndis: spelling fixes in comments.

No functional change.
fc01419148d065603607b1008d536431465f3bc3 26-Apr-2016 pfg <pfg@FreeBSD.org> sys: extend use of the howmany() macro when available.

We have a howmany() macro in the <sys/param.h> header that is
convenient to re-use as it makes things easier to read.
318c4f97e694c1972b55450cafe914f39977d179 22-May-2015 jkim <jkim@FreeBSD.org> CALLOUT_MPSAFE has lost its meaning since r141428, i.e., for more than ten
years for head. However, it is continuously misused as the mpsafe argument
for callout_init(9). Deprecate the flag and clean up callout_init() calls
to make them more consistent.

Differential Revision: https://reviews.freebsd.org/D2613
Reviewed by: jhb
MFC after: 2 weeks
eb1a5f8de9f7ea602c373a710f531abbf81141c4 21-Feb-2014 gjb <gjb@FreeBSD.org> Move ^/user/gjb/hacking/release-embedded up one directory, and remove
^/user/gjb/hacking since this is likely to be merged to head/ soon.

Sponsored by: The FreeBSD Foundation
6b01bbf146ab195243a8e7d43bb11f8835c76af8 27-Dec-2013 gjb <gjb@FreeBSD.org> Copy head@r259933 -> user/gjb/hacking/release-embedded for initial
inclusion of (at least) arm builds with the release.

Sponsored by: The FreeBSD Foundation
de4ecca21340ce4d0bf9182cac133c14e031218e 07-Aug-2013 jeff <jeff@FreeBSD.org> Replace kernel virtual address space allocation with vmem. This provides
transparent layering and better fragmentation.

- Normalize functions that allocate memory to use kmem_*
- Those that allocate address space are named kva_*
- Those that operate on maps are named kmap_*
- Implement recursive allocation handling for kmem_arena in vmem.

Reviewed by: alc
Tested by: pho
Sponsored by: EMC / Isilon Storage Division
07ebfe1b9c18245d771125096d6654ee06f14c21 29-May-2012 kevlo <kevlo@FreeBSD.org> Make sure that each va_start has one and only one matching va_end,
especially in error cases.
e28679ec14f723663e64f5b4cd256d9d28129d97 30-Dec-2011 dim <dim@FreeBSD.org> In sys/compat/ndis/subr_ntoskrnl.c, change the RtlFillMemory function
definition from K&R to ANSI, to avoid a clang warning about the uint8_t
parameter being promoted to int, which is not compatible with the type
declared in the earlier prototype.

MFC after: 1 week
6d9b42b4862ca331b22065d875de9cad9da72658 21-Feb-2011 brucec <brucec@FreeBSD.org> Fix typos - remove duplicate "the".

PR: bin/154928
Submitted by: Eitan Adler <lists at eitanadler.com>
MFC after: 3 days
caeebe8c54f48a26f3b4c95db3431267540067a5 19-Jan-2011 mdf <mdf@FreeBSD.org> Fix a few more SYSCTL_PROC() that were missing a CTLFLAG type specifier.
bd1f37ab1768b85d2f93d751b7151a2f4103c154 06-Dec-2010 bschmidt <bschmidt@FreeBSD.org> Implement NdisGetRoutineAddress and MmGetSystemRoutineAddress used in
newer Ralink drivers.

Submitted by: Paul B Mahol <onemda at gmail.com>
2fe8bd5bcc35ad602c1c34570e270624bb4e1e66 29-Nov-2010 bschmidt <bschmidt@FreeBSD.org> Add a dummy for IoOpenDeviceRegistryKey().

With that change the Atheros 9xxx driver is actually usable and does not
panic anymore.

Submitted by: Paul B Mahol <onemda at gmail.com>
MFC after: 2 weeks
77837b201a907898ee7c79f6a8584102187a089a 23-Nov-2010 bschmidt <bschmidt@FreeBSD.org> Add prototype for InitializeSListHead().
b1be2833eb4cb5b1dac766598cf3d578297bf653 23-Nov-2010 bschmidt <bschmidt@FreeBSD.org> Add a few functions used in newer drivers. Fix RtlCompareMemory() while

Submitted by: Paul B Mahol <onemda@gmail.com>
82896fc74f46ba5f27ba584ae8f368f7d6da8d12 22-Nov-2010 bschmidt <bschmidt@FreeBSD.org> Resurrect amd64 support.
- Many drivers on amd64 are picking system uptime, interrupt time and ticks
via global data structure instead of calling functions for performance
reasons. For now just patch such address so driver will not trigger page
fault when trying to access such data. In future, additional callout may
be added to update data in periodic intervals.
- On amd64 we need to allocate "shadow space" on stack before calling any

Submitted by: Paul B Mahol <onemda at gmail.com>
06a992a873410e4809abaea04c0f44bd903088ff 22-Nov-2010 bschmidt <bschmidt@FreeBSD.org> Prefer pmap_extract() over pmap_kextract() as done in MmIsAddressValid().
According to the comment for MmIsAddressValid() there are issues on PAE
kernels using pmap_kextract().

Submitted by: Paul B Mahol <onemda at gmail.com>
79e78b2c61c034f70491270cd04b4c5672a6c0c7 18-Nov-2010 dim <dim@FreeBSD.org> Sync: merge r215396 through r215463 from ^/head.
389cf6e63104fad1902eb97d7f7f4deba10390ac 17-Nov-2010 bschmidt <bschmidt@FreeBSD.org> Fix a panic on i386 for drivers using MmAllocateContiguousMemory()
and MmAllocateContiguousMemorySpecifyCache().

Those two functions take 64-bit variable(s) for their arguments. On i386
that takes additional 32-bit variable per argument. This is required so
that windrv_wrap() can correctly wrap function that miniport driver calls
with stdcall convention. Similar explanation is provided in subr_ndis.c for
other functions.

Submitted by: Paul B Mahol <onemda at gmail.com>
87fbb488d42ee452f32782e83f68e4f3e4834c97 17-Nov-2010 bschmidt <bschmidt@FreeBSD.org> Use kmem_alloc_contig() to honour the cache_type variable.

Pointed out by: alc
b1835fd2117bc2a167fad828131af71d691130b5 11-Nov-2010 bschmidt <bschmidt@FreeBSD.org> According to specs for MmAllocateContiguousMemorySpecifyCache() physically
contiguous memory with requested restrictions must be allocated.

Submitted by: Paul B Mahol <onemda at gmail.com>
7edbc46989f9ba57f8a8dd4d0a0f662abacdb9cc 04-Nov-2010 bschmidt <bschmidt@FreeBSD.org> Remove 4.x, 5.x and 6.x compatibility bits.

Submitted by: Paul B Mahol <onemda at gmail.com>
09f9c897d33c41618ada06fbbcf1a9b3812dee53 19-Oct-2010 jamie <jamie@FreeBSD.org> A new jail(8) with a configuration file, to replace the work currently done
by /etc/rc.d/jail.
b942a323706046076fe8c04fdc4db45c0c9d4a4c 05-Oct-2010 thompsa <thompsa@FreeBSD.org> Use the printf-like capability from kproc_create().

Submitted by: Paul B Mahol
f1216d1f0ade038907195fc114b7e630623b402c 19-Mar-2010 delphij <delphij@FreeBSD.org> Create a custom branch where I will be able to do the merge.
898a75fb36704fbd1597093326afa5a03fffb604 02-Nov-2009 rpaulo <rpaulo@FreeBSD.org> Big style cleanup. While there remove references to FreeBSD versions
older than 6.0.

Submitted by: Paul B Mahol <onemda at gmail.com>
bcc40d445d09395afa286b5446648255d2cb5968 18-Mar-2009 weongyo <weongyo@FreeBSD.org> If the caller sets irp_usriostat or irp_usrevent it try to process it
whatever the IRP flag is because some drivers (eg. RTL8187L NDIS driver)
call IoCompleteRequest() without setting flags. It will prevent waiting
a event forever at attach.
6d523cd42af824d128b343edb51f35a859902554 07-Mar-2009 weongyo <weongyo@FreeBSD.org> o port NDIS USB support from USB1 to the new usb(USB2).
o implement URB_FUNCTION_ABORT_PIPE handling.
o remove unused code related with canceling the timer list for USB
o whitespace cleanup and style(9)

Obtained from: hps's original patch
e5bfcba0804aec97eaffc409174ebf4d4fe91cca 24-Feb-2009 rdivacky <rdivacky@FreeBSD.org> Change the functions to ANSI in those cases where it breaks promotion
to int rule. See ISO C Standard: SS6.7.5.3:15.

Approved by: kib (mentor)
Reviewed by: warner
Tested by: silence on -current
0f8825b3f7e9bfd96fc59b8c4404742798efbb5a 27-Dec-2008 weongyo <weongyo@FreeBSD.org> Integrate the NDIS USB support code to CURRENT.

Now the NDISulator supports NDIS USB drivers that it've tested with
devices as follows:

- Anygate XM-142 (Conexant)
- Netgear WG111v2 (Realtek)
- U-Khan UW-2054u (Marvell)
- Shuttle XPC Accessory PN20 (Realtek)
- ipTIME G054U2 (Ralink)
- ZyXEL G-200v2 (ZyDAS)

All of them succeeded to attach and worked though there are still some
problems that it's expected to be solved.

To use NDIS USB support, you should rebuild and install ndiscvt(8) and
if you encounter a problem to attach please set `hw.ndisusb.halt' to
0 then retry.

I expect no changes of the NDIS code for PCI, PCMCIA devices.

Obtained from: //depot/projects/ndisusb/...
19b6af98ec71398e77874582eb84ec5310c7156f 22-Nov-2008 dfr <dfr@FreeBSD.org> Clone Kip's Xen on stable/6 tree so that I can work on improving FreeBSD/amd64
performance in Xen's HVM mode.
cf5320822f93810742e3d4a1ac8202db8482e633 19-Oct-2008 lulf <lulf@FreeBSD.org> - Import the HEAD csup code which is the basis for the cvsmode work.
2baff21378879fa4c222b032051e0dd6d6e77866 22-Aug-2008 thompsa <thompsa@FreeBSD.org> MFC r174150, r174240, r179009, r179720

Sync sys/compat/ndis to HEAD.

- Correct the calculation for the number of 100ns intervals since January 1,
1601. The 1601 - 1970 period was in seconds rather than 100ns units.
- Remove duplication by having NdisGetCurrentSystemTime call ntoskrnl_time.
- Implement functions required by some ndis drivers.
- Fix a panic when it occurred during initializing the ndis driver because it
try to read network address through ifnet structure which is NULL until the
ndis driver's initialization is finished.
- fix a page fault that it occurred during ifp is NULL. This bug happens when
NDIS driver's initialization is failed and NDIS driver's trying to call
b3b2795fc5a3ccd5d0477144619baf7a0b812f82 21-Aug-2008 weongyo <weongyo@FreeBSD.org> MFC r179423

Fix a panic that a priority value which is passed to cv_broadcastpri(9)
can be < 0. We don't ignore a `increment' argument but at least we keep
a priority value of NDIS threads over PRI_MIN_KERN.

Reviewed by: thompsa
cb08d7f87eca2f96b0b8babce9217f00e97fbe53 16-Jul-2008 cokane <cokane@FreeBSD.org> MFC of r179806 to 7-STABLE:

Silence warning about missing IoGetDeviceObjectPointer by implementing
a simple stub that always returns STATUS_SUCCESS.

Submitted by: Paul B. Mahol <onemda@gmail.com>
Reviewed by: thompsa
974e7b1858717fc53ebd08e616921d3e25b6aac2 15-Jun-2008 cokane <cokane@FreeBSD.org> Silence warning about missing IoGetDeviceObjectPointer by implementing
a simple stub that always returns STATUS_SUCCESS.

Submitted by: Paul B. Mahol <onemda@gmail.com>
Reviewed by: thompsa
MFC after: 1 week
1ea90a0deae5bb3d69f5f91d039927b404236885 30-May-2008 weongyo <weongyo@FreeBSD.org> Fix a panic that a priority value which is passed to cv_broadcastpri(9)
can be < 0. We don't ignore a `increment' argument but at least we keep
a priority value of NDIS threads over PRI_MIN_KERN.

Reviewed by: thompsa
8102a58c3d7567639135ae7215fda70aeb2df704 30-Mar-2008 rwatson <rwatson@FreeBSD.org> Merge amd64/machdep.c:1.680, amd64/mp_watchdog.c:1.6,
uart_dev_at91usart.c:1.13, scsi_low.h:1.9, subr_ntoskrnl.c:1.94,
OsdDebug.c:1.14, dcons_os.c:1.20, ofw_consle.c:1.37,
dev/sio.c:1.473, syscons.c:1.454, uart_core.c:1.23,
union_subr.c:1.96, i386/machdep.c:1.664, i386/mp_watchdog.c:1.6,
ia64/machdep.c:1.228, kern_clock.c:1.206, kern_shutdown.c:1.186,
subr_kdb.c:1.25, subr_witness.c:1.239, vfs_subr.c:1.711,
ng_base.c:1.140, cbus/sio.c:1.247, pc98/machdep.c:1.399,
aim/machdep.c:1.107, pswitch.c:1.7, mac_test.c:19.3,
psycho.c:1.73, sparc64/machdep.c:1.140, sparc64/trap.c:1.89,
hvcons.c:1.7, sun4v/machdep.c:1.17, sun4v/trap.c:1.17, kdb.h:1.6
from HEAD to RELENG_7:

Add a new 'why' argument to kdb_enter(), and a set of constants to use
for that argument. This will allow DDB to detect the broad category of
reason why the debugger has been entered, which it can use for the
purposes of deciding which DDB script to run.

Assign approximate why values to all current consumers of the
kdb_enter() interface.

For ABI/KPI reasons, the MFC creates a new function, kdb_enter_why(),
with the new argument, updating existing consumers to use that,
preserving kdb_enter() with the current argument, and wrapping it around
bdee30611dab246a5227856892385a02c7352f12 25-Dec-2007 rwatson <rwatson@FreeBSD.org> Add a new 'why' argument to kdb_enter(), and a set of constants to use
for that argument. This will allow DDB to detect the broad category of
reason why the debugger has been entered, which it can use for the
purposes of deciding which DDB script to run.

Assign approximate why values to all current consumers of the
kdb_enter() interface.
b56e8f172a7ef58c61c47adb249e38cacab661ad 03-Dec-2007 thompsa <thompsa@FreeBSD.org> Implement functions required by some ndis drivers.

NdisIMCopySendPerPacketInfo [1]
KeQuerySystemTime [1]
KeTickCount [1]
strncat [1]

Submitted by: Marcin Simonides [1]
200d23553e98c71f31c241b13845cb1f9658402b 02-Dec-2007 thompsa <thompsa@FreeBSD.org> Correct the calculation for the number of 100ns intervals since
January 1, 1601. The 1601 - 1970 period was in seconds rather than 100ns

Remove duplication by having NdisGetCurrentSystemTime call ntoskrnl_time.
51d643caa6efc11780104da450ee36a818170f81 20-Oct-2007 julian <julian@FreeBSD.org> Rename the kthread_xxx (e.g. kthread_create()) calls
to kproc_xxx as they actually make whole processes.
Thos makes way for us to add REAL kthread_create() and friends
that actually make theads. it turns out that most of these
calls actually end up being moved back to the thread version
when it's added. but we need to make this cosmetic change first.

I'd LOVE to do this rename in 7.0 so that we can eventually MFC the
new kthread_xxx() calls.
c60c38c413e8b4b35c49caa96d16ab78d248d748 22-Jul-2007 thompsa <thompsa@FreeBSD.org> ndis will signal the kthread to exit and then sleep on the proc pointer to
be woken up by kthread_exit. This is racey and in some cases the kthread will
exit before ndis gets around to sleep so it will be stuck indefinitely. This
change reuses the kq_exit variable to indicate that the thread has gone and
will loop on tsleep with a timeout waiting for it. If the kthread has already
exited then it will not sleep at all.

Approved by: re (rwatson)
91d150179059555ef497f4b5b5a560fdb24e472f 05-Jun-2007 jeff <jeff@FreeBSD.org> Commit 14/14 of sched_lock decomposition.
- Use thread_lock() rather than sched_lock for per-thread scheduling
- Use the per-process spinlock rather than the sched_lock for per-process
scheduling synchronization.

Tested by: kris, current@
Tested on: i386, amd64, ULE, 4BSD, libthr, libkse, PREEMPTION, etc.
Discussed with: kris, attilio, kmacy, jhb, julian, bde (small parts each)
b6c9f6e18ea33e594cd822ee7f8d967f468dbde4 26-Jan-2007 sam <sam@FreeBSD.org> MFC 1.88: add entry points required by newer broadcom wireless driver
874c920cbc984f1171685f69e2cc3c690b178aa3 25-Dec-2006 sam <sam@FreeBSD.org> add entry points required by newer broadcom wireless driver

PR: kern/106131
Submitted by: Scot Hetzel
MFC after: 2 weeks
ef310efff89c7c9b24e149c33a698707417d8367 16-May-2006 phk <phk@FreeBSD.org> Since DELAY() was moved, most <machine/clock.h> #includes have been
111400b259c7ddf7960f78d24ffcc02c913dfc86 16-Dec-2005 wpaul <wpaul@FreeBSD.org> Ok, let's try that again. MFC recent changes from -current, this time
to the right branch (interrupt handler API fixes, Ralink RT2500 deadlock
with wpa_supplicant).
3d571e2f28283e633fbc3eade19d120a71bb0e87 23-Nov-2005 wpaul <wpaul@FreeBSD.org> Somehow memmove() got mapped to memset() in the patch table. Create a
real memmove() implementation and use that instead.
0b2e0bd48c924a16c0a3f0278bdd5c3e3ba0e4cf 20-Nov-2005 wpaul <wpaul@FreeBSD.org> Correct the API for Windows interupt handling a little. The prototype
for a Windows ISR is 'BOOLEAN isrfunc(KINTERRUPT *, void *)' meaning
the ISR get a pointer to the interrupt object and a context pointer,
and returns TRUE if the ISR determines the interrupt was really generated
by the associated device, or FALSE if not.

I had mistakenly used 'void isrfunc(void *)' instead. It happens the
only thing this affects is the internal ndis_intr() ISR in subr_ndis.c,
but it should be fixed just in case we ever need to register a real
Windows ISR vi IoConnectInterrupt().

For NDIS miniports that provide a MiniportISR() method, the 'is_our_intr'
value returned by the method serves as the return value from ndis_isr(),
and 'call_isr' is used to decide whether or not to schedule the interrupt
handler via DPC. For drivers that only supply MiniportEnableInterrupt()
and MiniportDisableInterrupt() methods, call_isr is always TRUE and
is_our_intr is always FALSE.

In the end, there should be no functional changes, except that now
ntoskrnl_intr() can terminate early once it finds the ISR that wants
to service the interrupt.
23ffac65563245e93b825f24d9d654019e0a0d5e 10-Nov-2005 wpaul <wpaul@FreeBSD.org> MFC: add RtlZeroMemory() and RtlCopyMemory() for Broadcom amd64 driver.
358decbed5c7bc10eb5ed65da5b7581a0fe3a18c 10-Nov-2005 wpaul <wpaul@FreeBSD.org> Implement RtlZeroMemory() and RtlCopyMemory(). This seems to allow
the Broadcom Win64 wireless driver for the BCM4318 to work on amd64.
80d777c8ec33a6a3e4a50e6236f85509b32cdae2 06-Nov-2005 wpaul <wpaul@FreeBSD.org> MFC: merge changes from head to pacify Intel 2200BG/2915/ABG driver.
6daa19f5d466032385dc530f2c224d4c762e04f9 06-Nov-2005 wpaul <wpaul@FreeBSD.org> The latest version of the Intel 2200BG/2915ABG driver ( from
Intel's web site requires some minor tweaks to get it to work:

- The driver seems to have been released with full WMI tracing enabled,
and makes references to some WMI APIs, namely IoWMIRegistrationControl(),
WmiQueryTraceInformation() and WmiTraceMessage(). Only the first
one is ever called (during intialization). These have been implemented
as do-nothing stubs for now. Also added a definition for STATUS_NOT_FOUND
to ntoskrnl_var.h, which is used as a return code for one of the WMI

- The driver references KeRaiseIrqlToDpcLevel() and KeLowerIrql()
(the latter as a function, which is unusual because normally
KeLowerIrql() is a macro in the Windows DDK that calls KfLowewIrql()).
I'm not sure why these are being called since they're not really
part of WDM. Presumeably they're being used for backwards
compatibility with old versions of Windows. These have been
implemented in subr_hal.c. (Note that they're _stdcall routines
instead of _fastcall.)

- When querying the OID_802_11_BSSID_LIST OID to get a BSSID list,
you don't know ahead of time how many networks the NIC has found
during scanning, so you're allowed to pass 0 as the list length.
This should cause the driver to return an 'insufficient resources'
error and set the length to indicate how many bytes are actually
needed. However for some reason, the Intel driver does not honor
this convention: if you give it a length of 0, it returns some
other error and doesn't tell you how much space is really needed.
To get around this, if using a length of 0 yields anything besides
the expected error case, we arbitrarily assume a length of 64K.
This is similar to the hack that wpa_supplicant uses when doing
a BSSID list query.
7b9892860426a6574b54cba004b34e81f62d45f1 06-Nov-2005 wpaul <wpaul@FreeBSD.org> MFC recent changes, bring all 3 branches back into sync again
c104267c1a97cafb9b2e7707382601a452ced831 02-Nov-2005 wpaul <wpaul@FreeBSD.org> Tests with my dual Opteron system have shown that it's possible
for code to start out on one CPU when thunking into Windows
mode in ctxsw_utow(), and then be pre-empted and migrated to another
CPU before thunking back to UNIX mode in ctxsw_wtou(). This is
bad, because then we can end up looking at the wrong 'thread environment
block' when trying to come back to UNIX mode. To avoid this, we now
pin ourselves to the current CPU when thunking into Windows code.

Few other cleanups, since I'm here:

- Get rid of the ndis_isr(), ndis_enable_interrupt() and
ndis_disable_interrupt() wrappers from kern_ndis.c and just invoke
the miniport's methods directly in the interrupt handling routines
in subr_ndis.c. We may as well lose the function call overhead,
since we don't need to export these things outside of ndis.ko
now anyway.

- Remove call to ndis_enable_interrupt() from ndis_init() in if_ndis.c.
We don't need to do it there anyway (the miniport init routine handles
it, if needed).

- Fix the logic in NdisWriteErrorLogEntry() a little.

- Change some NDIS_STATUS_xxx codes in subr_ntoskrnl.c into STATUS_xxx

- Handle kthread_create() failure correctly in PsCreateSystemThread().
87ccfda2f10e62be3f57298a3f9140a436892158 01-Nov-2005 wpaul <wpaul@FreeBSD.org> Clean up one remaining 'multiple DPC thread' bogon: only bzero() one
sizeof(kq_queue), not sizeof(kq_queue) * mp_ncpus.
14b480eac9940fb4edc06d3dde5a27bc28f18e6f 27-Oct-2005 wpaul <wpaul@FreeBSD.org> MFC: synchronize the NDISulator with the head and RELENG_5 branches,
add -D ndis support to wpa_supplicant

Approved by: re
b382eabb5fab57ecfeb778d08fd7565f128ddd68 26-Oct-2005 wpaul <wpaul@FreeBSD.org> Minor nit: in ntoskrnl_finddev(), only free the 'children' device_t
array if device_find_children() actually returned a non-NULL array pointer.
a16098473846c54b54bd1b74ca434605687746c7 26-Oct-2005 wpaul <wpaul@FreeBSD.org> Get rid of the timer tracking and reaping code in NdisMInitializeTimer()
and ndis_halt_nic(). It's been disabled for some time anyway, and
it turns out there's a possible deadlock in NdisMInitializeTimer() when
acquiring the miniport block lock to modify the timer list: it's
possible for a driver to call NdisMInitializeTimer() when the miniport
block lock has already been acquired by an earlier piece of code. You
can't acquire the same spinlock twice, so this can deadlock.

Also, implement MmMapIoSpace() and MmUnmapIoSpace(), and make
NdisMMapIoSpace() and NdisMUnmapIoSpace() use them. There are some
drivers that want MmMapIoSpace() and MmUnmapIoSpace() so that they can
map arbitrary register spaces not directly associated with their
device resources. For example, there's an Atheros driver for
a miniPci card (0x168C:0x1014) on the IBM Thinkpad x40 that wants
to map some I/O spaces at 0xF00000 and 0xE00000 which are held by
the acpi0 device. I don't know what it wants these ranges for,
but if it can't map and access them, the MiniportInitialize() method
be0b87ae9318f36ecbbd0aec85672bc551305f66 22-Oct-2005 wpaul <wpaul@FreeBSD.org> Make the multiple DPC threads an option, and create only one by default.
This avoids the need for sched_bind() in the default case so that you
can start up the NDIS subsystem at boot time when only CPU 0 is running.

There are potentially ways to fix it so that the DPC threads aren't
started until after the other CPUs are launched, but doing it correctly
is tricky. You need to defer the startup of the ntoskrnl subsystem
(ntoskrnl_libinit()), not just defer ndis_attach().

For now, I don't think it will make much difference having just the
single DPC thread (I started out with just one anyway). Note that this
turns the KeSetTargetProcessorDpc() routine into a no-op, since the
CPU number in struct kdpc is now ignored.
8be176b07bf4928315544e3973a80e096cbffa37 21-Oct-2005 wpaul <wpaul@FreeBSD.org> Correct the macro definition for KeRaiseIrql(). The official API
is KeRaiseIrql(newirql, &oldirql), not oldirql = KeRaiseIrql(newirql).
(The macro ultimately translates to KfRaiseIrql() which does use
the latter API, so this has no effect on generated code.)

Also, wait for thread termination the right way: kthread_exit()
will ultimately do a wakeup(td->td_proc). This is the event we
should wait on. Eliminate the previous synchronization machinery
for this since it was never guaranteed to work correctly.
b76fb84305d303c2dfaf26c9d487e9989b946adb 20-Oct-2005 wpaul <wpaul@FreeBSD.org> Use sched_bind() to make sure the DPC threads are bound to the correct
processor, to insure DPC thread 0 runs on CPU0, DPC thread 1 runs on
CPU1, and so on.

Elevate the priority of the workitem threads, though don't use as
high a priority as the DPC threads.
81737fff083ffbd9a4647cdb650c88e3b2ddfb0b 18-Oct-2005 wpaul <wpaul@FreeBSD.org> Another round of cleanups and fixes:

- Change ndis_return() from a DPC to a workitem so that it doesn't
run at DISPATCH_LEVEL (with the dispatcher lock held).

- In if_ndis.c, submit packets to the stack via (*ifp->if_input)() in
a workitem instead of doing it directly in ndis_rxeof(), because
ndis_rxeof() runs in a DPC, and hence at DISPATCH_LEVEL. This
implies that the 'dispatch level' mutex for the current CPU is
being held, and we don't want to call if_input while holding
any locks.

- Reimplement IoConnectInterrupt()/IoDisconnectInterrupt(). The original
approach I used to track down the interrupt resource (by scanning
the device tree starting at the nexus) is prone to problems when
two devices share an interrupt. (E.g removing ndis1 might disable
interrupts for ndis0.) The new approach is to multiplex all the
NDIS interrupts through a common internal dispatcher (ntoskrnl_intr())
and allow IoConnectInterrupt()/IoDisconnectInterrupt() to add or
remove interrupts from the dispatch list.

- Implement KeAcquireInterruptSpinLock() and KeReleaseInterruptSpinLock().

- Change the DPC and workitem threads to use the KeXXXSpinLock
API instead of mtx_lock_spin()/mtx_unlock_spin().

- Simplify the NdisXXXPacket routines by creating an actual
packet pool structure and using the InterlockedSList routines
to manage the packet queue.

- Only honor the value returned by OID_GEN_MAXIMUM_SEND_PACKETS
for serialized drivers. For deserialized drivers, we now create
a packet array of 64 entries. (The Microsoft DDK documentation
says that for deserialized miniports, OID_GEN_MAXIMUM_SEND_PACKETS
is ignored, and the driver for the Marvell 8335 chip, which is
a deserialized miniport, returns 1 when queried.)

- Clean up timer handling in subr_ntoskrnl.

- Add the following conditional debugging code:
NTOSKRNL_DEBUG_TIMERS - add debugging and stats for timers
NDIS_DEBUG_PACKETS - add extra sanity checking for NdisXXXPacket API
NTOSKRNL_DEBUG_SPINLOCKS - add test for spinning too long

- In kern_ndis.c, always start the HAL first and shut it down last,
since Windows spinlocks depend on it. Ntoskrnl should similarly be
started second and shut down next to last.
0ce580e541845da75bdd8e15bc6abdd6c573eb4f 12-Oct-2005 wpaul <wpaul@FreeBSD.org> Convert ndis_set_info() and ndis_get_info() from using msleep()
to KeSetEvent()/KeWaitForSingleObject(). Also make object argument
of KeWaitForSingleObject() a void * like it's supposed to be.
ef07dbe57fe381dac96f0b1470d99bd3a2ccd3aa 10-Oct-2005 wpaul <wpaul@FreeBSD.org> This commit makes a big round of updates and fixes many, many things.

First and most importantly, I threw out the thread priority-twiddling
implementation of KeRaiseIrql()/KeLowerIrq()/KeGetCurrentIrql() in
favor of a new scheme that uses sleep mutexes. The old scheme was
really very naughty and sought to provide the same behavior as
Windows spinlocks (i.e. blocking pre-emption) but in a way that
wouldn't raise the ire of WITNESS. The new scheme represents
'DISPATCH_LEVEL' as the acquisition of a per-cpu sleep mutex. If
a thread on cpu0 acquires the 'dispatcher mutex,' it will block
any other thread on the same processor that tries to acquire it,
in effect only allowing one thread on the processor to be at
'DISPATCH_LEVEL' at any given time. It can then do the 'atomic sit
and spin' routine on the spinlock variable itself. If a thread on
cpu1 wants to acquire the same spinlock, it acquires the 'dispatcher
mutex' for cpu1 and then it too does an atomic sit and spin to try
acquiring the spinlock.

Unlike real spinlocks, this does not disable pre-emption of all
threads on the CPU, but it does put any threads involved with
the NDISulator to sleep, which is just as good for our purposes.

This means I can now play nice with WITNESS, and I can safely do
things like call malloc() when I'm at 'DISPATCH_LEVEL,' which
you're allowed to do in Windows.

Next, I completely re-wrote most of the event/timer/mutex handling
and wait code. KeWaitForSingleObject() and KeWaitForMultipleObjects()
have been re-written to use condition variables instead of msleep().
This allows us to use the Windows convention whereby thread A can
tell thread B "wake up with a boosted priority." (With msleep(), you
instead have thread B saying "when I get woken up, I'll use this
priority here," and thread A can't tell it to do otherwise.) The
new KeWaitForMultipleObjects() has been better tested and better
duplicates the semantics of its Windows counterpart.

I also overhauled the IoQueueWorkItem() API and underlying code.
Like KeInsertQueueDpc(), IoQueueWorkItem() must insure that the
same work item isn't put on the queue twice. ExQueueWorkItem(),
which in my implementation is built on top of IoQueueWorkItem(),
was also modified to perform a similar test.

I renamed the doubly-linked list macros to give them the same names
as their Windows counterparts and fixed RemoveListTail() and
RemoveListHead() so they properly return the removed item.

I also corrected the list handling code in ntoskrnl_dpc_thread()
and ntoskrnl_workitem_thread(). I realized that the original logic
did not correctly handle the case where a DPC callout tries to
queue up another DPC. It works correctly now.

I implemented IoConnectInterrupt() and IoDisconnectInterrupt() and
modified NdisMRegisterInterrupt() and NdisMDisconnectInterrupt() to
use them. I also tried to duplicate the interrupt handling scheme
used in Windows. The interrupt handling is now internal to ndis.ko,
and the ndis_intr() function has been removed from if_ndis.c. (In
the USB case, interrupt handling isn't needed in if_ndis.c anyway.)

NdisMSleep() has been rewritten to use a KeWaitForSingleObject()
and a KeTimer, which is how it works in Windows. (This is mainly
to insure that the NDISulator uses the KeTimer API so I can spot
any problems with it that may arise.)

KeCancelTimer() has been changed so that it only cancels timers, and
does not attempt to cancel a DPC if the timer managed to fire and
queue one up before KeCancelTimer() was called. The Windows DDK
documentation seems to imply that KeCantelTimer() will also call
KeRemoveQueueDpc() if necessary, but it really doesn't.

The KeTimer implementation has been rewritten to use the callout API
directly instead of timeout()/untimeout(). I still cheat a little in
that I have to manage my own small callout timer wheel, but the timer
code works more smoothly now. I discovered a race condition using
timeout()/untimeout() with periodic timers where untimeout() fails
to actually cancel a timer. I don't quite understand where the race
is, using callout_init()/callout_reset()/callout_stop() directly
seems to fix it.

I also discovered and fixed a bug in winx32_wrap.S related to
translating _stdcall calls. There are a couple of routines
(i.e. the 64-bit arithmetic intrinsics in subr_ntoskrnl) that
return 64-bit quantities. On the x86 arch, 64-bit values are
returned in the %eax and %edx registers. However, it happens
that the ctxsw_utow() routine uses %edx as a scratch register,
and x86_stdcall_wrap() and x86_stdcall_call() were only preserving
%eax before branching to ctxsw_utow(). This means %edx was getting
clobbered in some cases. Curiously, the most noticeable effect of this
bug is that the driver for the TI AXC110 chipset would constantly drop
and reacquire its link for no apparent reason. Both %eax and %edx
are preserved on the stack now. The _fastcall and _regparm
wrappers already handled everything correctly.

I changed if_ndis to use IoAllocateWorkItem() and IoQueueWorkItem()
instead of the NdisScheduleWorkItem() API. This is to avoid possible
deadlocks with any drivers that use NdisScheduleWorkItem() themselves.

The unicode/ansi conversion handling code has been cleaned up. The
internal routines have been moved to subr_ntoskrnl and the
RtlXXX routines have been exported so that subr_ndis can call them.
This removes the incestuous relationship between the two modules
regarding this code and fixes the implementation so that it honors
the 'maxlen' fields correctly. (Previously it was possible for
NdisUnicodeStringToAnsiString() to possibly clobber memory it didn't
own, which was causing many mysterious crashes in the Marvell 8335

The registry handling code (NdisOpen/Close/ReadConfiguration()) has
been fixed to allocate memory for all the parameters it hands out to
callers and delete whem when NdisCloseConfiguration() is called.
(Previously, it would secretly use a single static buffer.)

I also substantially updated if_ndis so that the source can now be
built on FreeBSD 7, 6 and 5 without any changes. On FreeBSD 5, only
WEP support is enabled. On FreeBSD 6 and 7, WPA-PSK support is enabled.

The original WPA code has been updated to fit in more cleanly with
the net80211 API, and to eleminate the use of magic numbers. The
ndis_80211_setstate() routine now sets a default authmode of OPEN
and initializes the RTS threshold and fragmentation threshold.
The WPA routines were changed so that the authentication mode is
always set first, followed by the cipher. Some drivers depend on
the operations being performed in this order.

I also added passthrough ioctls that allow application code to
directly call the MiniportSetInformation()/MiniportQueryInformation()
methods via ndis_set_info() and ndis_get_info(). The ndis_linksts()
routine also caches the last 4 events signalled by the driver via
NdisMIndicateStatus(), and they can be queried by an application via
a separate ioctl. This is done to allow wpa_supplicant to directly
program the various crypto and key management options in the driver,
allowing things like WPA2 support to work.

d732ff5ca26d05955ce97f2f7b9f6bb7d117120f 08-Jul-2005 rik <rik@FreeBSD.org> Use implicit type cast for ->k_lock to fix compilation of ndis
as a part of the GENERIC kernel with INVARIANT* and WITNESS*
turned off.
(For non GENERIC kernel KTR and MUTEX_PROFILING should be also

Submitted by: Eygene A. Ryabinkin <rea at rea dot mbslab dot kiae dot ru>
Approved by: re (scottl)
PR: 81767
0fce92f5c4e1bb05c348b1c481e9e4997a7900b4 29-May-2005 nyan <nyan@FreeBSD.org> Remove bus_{mem,p}io.h and related code for a micro-optimization on i386
and amd64. The optimization is a trivial on recent machines.

Reviewed by: -arch (imp, marcel, dfr)
8e4107ff8fb214fe5141e4fbcaf07d79be8054e5 19-May-2005 wpaul <wpaul@FreeBSD.org> Fix some of the things I broke so that the SMC2602W (AMD Am1772) driver
works again.

This driver uses NdisScheduleWorkItem(), and we have to take special steps
to insure that its workitems don't collide with any of the other workitems
used by the NDISulator. In particular, if one of the driver's work jobs
blocks, it can prevent NdisMAllocateSharedMemoryAsync() from completing
when expected.

The original hack to fix this was to have NdisMAllocateSharedMemoryAsync()
defer its work to the DPC queue instead of the general task queue. To
fix it now, I decided to add some additional workitem threads. (There's
supposed to be a pool of worker threads in Windows anyway.) Currently,
there are 4. There should be at least 2. One is reserved for the legacy
ExQueueWorkItem() API, while the others are used in round-robin by the
IoQueueWorkItem() API. NdisMAllocateSharedMemoryAsync() uses the latter
API while NdisScheduleWorkItem() uses the former, so the deadlock is

Fixed NdisMRegisterDevice()/NdisMDeregisterDevice() to work a little
more sensibly with the new driver_object/device_object framework. It
doesn't really register a working user-mode interface, but the existing
code was completely wrong for the new framework.

Fixed a couple of bugs dealing with the cancellation of events and
DPCs. When cancelling an event that's still on the timer queue (i.e.
hasn't expired yet), reset dh_inserted in its dispatch header to FALSE.
Previously, it was left set to TRUE, which would make a cancelled
timer appear to have not been cancelled. Also, when removing a DPC
from a queue, reset its list pointers, otherwise a cancelled DPC
might mistakenly be treated as still pending.

Lastly, fix the behavior of ntoskrnl_wakeup() when dealing with
objects that have nobody waiting on them: sync event objects get
their signalled state reset to FALSE, but notification objects
should still be set to TRUE.
36f8fdfd3601d88023dfc0b74e30a4cb6003cf7e 08-May-2005 wpaul <wpaul@FreeBSD.org> Correct the patch table entries for the 64-bit intrinsic math
routines (_alldiv(), _allmul(), _alludiv(), _aullmul(), etc...)
that use the _stdcall calling convention.

These routines all take two arguments, but the arguments are 64 bits wide.
On the i386 this means they each consume two 32-bit slots on the stack.
Consequently, when we specify the argument count in the IMPORT_SFUNC()
macro, we have to lie and claim there are 4 arguments instead of two.
This will cause the resulting i386 assembly wrapper to push the right
number of longwords onto the stack.

This fixes a crash I discovered with the RealTek 8180 driver, which
uses these routines a lot during initialization.
077b71e0fa3ad5840a2b555ba5e3a6a921112309 05-May-2005 wpaul <wpaul@FreeBSD.org> Avoid sleeping with mutex held in kern_ndis.c.

Remove unused fields from ndis_miniport_block.

Fix a bug in KeFlushQueuedDpcs() (we weren't calculating the kq pointer

In if_ndis.c, clear the IFF_RUNNING flag before calling ndis_halt_nic().

Add some guards in kern_ndis.c to avoid letting anyone invoke ndis_get_info()
or ndis_set_info() if the NIC isn't fully initialized. Apparently, mdnsd
will sometimes try to invoke the ndis_ioctl() routine at exactly the
wrong moment (to futz with its multicast filters) when the interface
comes up, and can trigger a crash unless we guard against it.
e9bace5ba16735b4fd2dbe727166b3720fbf5101 05-May-2005 wpaul <wpaul@FreeBSD.org> This commit makes a bunch of changes, some big, some not so big.

- Remove the old task threads from kern_ndis.c and reimplement them in
subr_ntoskrnl.c, in order to more properly emulate the Windows DPC
API. Each CPU gets its own DPC queue/thread, and each queue can
have low, medium and high importance DPCs. New APIs implemented:
KeSetTargetProcessorDpc(), KeSetImportanceDpc() and KeFlushQueuedDpcs().
(This is the biggest change.)

- Fix a bug in NdisMInitializeTimer(): the k_dpc pointer in the
nmt_timer embedded in the ndis_miniport_timer struct must be set
to point to the DPC, also embedded in the struct. Failing to do
this breaks dequeueing of DPCs submitted via timers, and in turn
breaks cancelling timers.

- Fix a bug in KeCancelTimer(): if the timer is interted in the timer
queue (i.e. the timeout callback is still pending), we have to both
untimeout() the timer _and_ call KeRemoveQueueDpc() to nuke the DPC
that might be pending. Failing to do this breaks cancellation of
periodic timers, which always appear to be inserted in the timer queue.

- Make use of the nmt_nexttimer field in ndis_miniport_timer: keep a
queue of pending timers and cancel them all in ndis_halt_nic(), prior
to calling MiniportHalt(). Also call KeFlushQueuedDpcs() to make sure
any DPCs queued by the timers have expired.

- Modify NdisMAllocateSharedMemory() and NdisMFreeSharedMemory() to keep
track of both the virtual and physical addresses of the shared memory
buffers that get handed out. The AirGo MIMO driver appears to have a bug
in it: for one of the segments is allocates, it returns the wrong
virtual address. This would confuse NdisMFreeSharedMemory() and cause
a crash. Why it doesn't crash Windows too I have no idea (from reading
the documentation for NdisMFreeSharedMemory(), it appears to be a violation
of the API).

- Implement strstr(), strchr() and MmIsAddressValid().

- Implement IoAllocateWorkItem(), IoFreeWorkItem(), IoQueueWorkItem() and
ExQueueWorkItem(). (This is the second biggest change.)

- Make NdisScheduleWorkItem() call ExQueueWorkItem(). (Note that the
ExQueueWorkItem() API is deprecated by Microsoft, but NDIS still uses
it, since NdisScheduleWorkItem() is incompatible with the IoXXXWorkItem()

- Change if_ndis.c to use the NdisScheduleWorkItem() interface for scheduling

With all these changes and fixes, the AirGo MIMO driver for the Belkin
F5D8010 Pre-N card now works. Special thanks to Paul Robinson
(paul dawt robinson at pwermedia dawt net) for the loan of a card
for testing.
b493dd59e2b39c6ee3f3016ffe21c427b8038eb8 24-Apr-2005 wpaul <wpaul@FreeBSD.org> Throw the switch on the new driver generation/loading mechanism. From
here on in, if_ndis.ko will be pre-built as a module, and can be built
into a static kernel (though it's not part of GENERIC). Drivers are
created using the new ndisgen(8) script, which uses ndiscvt(8) under
the covers, along with a few other tools. The result is a driver module
that can be kldloaded into the kernel.

A driver with foo.inf and foo.sys files will be converted into
foo_sys.ko (and foo_sys.o, for those who want/need to make static
kernels). This module contains all of the necessary info from the
.INF file and the driver binary image, converted into an ELF module.
You can kldload this module (or add it to /boot/loader.conf) to have
it loaded automatically. Any required firmware files can be bundled
into the module as well (or converted/loaded separately).

Also, add a workaround for a problem in NdisMSleep(). During system
bootstrap (cold == 1), msleep() always returns 0 without actually
sleeping. The Intel 2200BG driver uses NdisMSleep() to wait for
the NIC's firmware to come to life, and fails to load if NdisMSleep()
doesn't actually delay. As a workaround, if msleep() (and hence
ndis_thsuspend()) returns 0, use a hard DELAY() to sleep instead).
This is not really the right thing to do, but we can't really do much
else. At the very least, this makes the Intel driver happy.

There are probably other drivers that fail in this way during bootstrap.
Unfortunately, the only workaround for those is to avoid pre-loading
them and kldload them once the system is running instead.
a3b2d3191d684cc192012aa160695992e980f7fc 11-Apr-2005 wpaul <wpaul@FreeBSD.org> Create new i386 windows/bsd thunking layer, similar to the amd64 thunking
layer, but with a twist.

The twist has to do with the fact that Microsoft supports structured
exception handling in kernel mode. On the i386 arch, exception handling
is implemented by hanging an exception registration list off the
Thread Environment Block (TEB), and the TEB is accessed via the %fs
register. The problem is, we use %fs as a pointer to the pcpu stucture,
which means any driver that tries to write through %fs:0 will overwrite
the curthread pointer and make a serious mess of things.

To get around this, Project Evil now creates a special entry in
the GDT on each processor. When we call into Windows code, a context
switch routine will fix up %fs so it points to our new descriptor,
which in turn points to a fake TEB. When the Windows code returns,
or calls out to an external routine, we swap %fs back again. Currently,
Project Evil makes use of GDT slot 7, which is all 0s by default.
I fully expect someone to jump up and say I can't do that, but I
couldn't find any code that makes use of this entry anywhere. Sadly,
this was the only method I could come up with that worked on both
UP and SMP. (Modifying the LDT works on UP, but becomes incredibly
complicated on SMP.) If necessary, the context switching stuff can
be yanked out while preserving the convention calling wrappers.

(Fortunately, it looks like Microsoft uses some special epilog/prolog
code on amd64 to implement exception handling, so the same nastiness
won't be necessary on that arch.)

The advantages are:

- Any driver that uses %fs as though it were a TEB pointer won't
clobber pcpu.
- All the __stdcall/__fastcall/__regparm stuff that's specific to
gcc goes away.

Also, while I'm here, switch NdisGetSystemUpTime() back to using
nanouptime() again. It turns out nanouptime() is way more accurate
than just using ticks(). On slower machines, the Atheros drivers
I tested seem to take a long time to associate due to the loss
in accuracy.
2e83169800e818d2307c5d9955262b6c072e62ce 30-Mar-2005 wpaul <wpaul@FreeBSD.org> Fix a possible mutex leak in KeSetTimerEx(): if timer is NULL, we
bail out without releasing the dispatcher lock. Move the lock acquisition
after the pointer test to avoid this.
3e1273271df9591a9b70dcd51fd2d0412782bf5b 28-Mar-2005 wpaul <wpaul@FreeBSD.org> More additions for amd64:

- On amd64, InterlockedPushEntrySList() and InterlockedPopEntrySList()
are mapped to ExpInterlockedPushEntrySList and
ExpInterlockedPopEntrySList() via macros (which do the same thing).
Add IMPORT_FUNC_MAP()s for these.

- Implement ExQueryDepthSList().
7f6e70f819a608814f22eafec1b10da1f6e0dfd5 28-Mar-2005 wpaul <wpaul@FreeBSD.org> Fix for amd64.
b1238bf60ea8e8c73ae8670ff6653b1bddc36e85 28-Mar-2005 wpaul <wpaul@FreeBSD.org> Fix another amd64 issue with lookaside lists: we initialize the
alloc and free routine pointers in the lookaside list with pointers
to ExAllocatePoolWithTag() and ExFreePool() (in the case where the
driver does not provide its own alloc and free routines). For amd64,
this is wrong: we have to use pointers to the wrapped versions of these
functions, not the originals.
12c3eeb4fa1b4cb21122c3550ba30283203f40d0 28-Mar-2005 wpaul <wpaul@FreeBSD.org> Tweak to hopefully make lookaside lists work on amd64: in Windows, the
nll_obsoletelock field in the lookaside list structure is only defined
for the i386 arch. For amd64, the field is gone, and different list
update routines are used which do their locking internally. Apparently
the Inprocomm amd64 driver uses lookaside lists. I'm not positive this
will make it work yet since I don't have an Inprocomm NIC to test, but
this needs to be fixed anyway.
959879757b82c7ca2f64f858a3d499579c9d884b 27-Mar-2005 wpaul <wpaul@FreeBSD.org> Finally bring an end to the great "make the Atheros NDIS driver
work on SMP" saga. After several weeks and much gnashing of teeth,
I have finally tracked down all the problems, despite their best
efforts to confound and annoy me.

Problem nunmber one: the Atheros windows driver is _NOT_ a de-serialized
miniport! It used to be that NDIS drivers relied on the NDIS library
itself for all their locking and serialization needs. Transmit packet
queues were all handled internally by NDIS, and all calls to
MiniportXXX() routines were guaranteed to be appropriately serialized.
This proved to be a performance problem however, and Microsoft
introduced de-serialized miniports with the NDIS 5.x spec. Microsoft
still supports serialized miniports, but recommends that all new drivers
written for Windows XP and later be deserialized. Apparently Atheros
wasn't listening when they said this.

This means (among other things) that we have to serialize calls to
MiniportSendPackets(). We also have to serialize calls to MiniportTimer()
that are triggered via the NdisMInitializeTimer() routine. It finally
dawned on me why NdisMInitializeTimer() takes a special
NDIS_MINIPORT_TIMER structure and a pointer to the miniport block:
the timer callback must be serialized, and it's only by saving the
miniport block handle that we can get access to the serialization
lock during the timer callback.

Problem number two: haunted hardware. The thing that was _really_
driving me absolutely bonkers for the longest time is that, for some
reason I couldn't understand, my test machine would occasionally freeze
or more frustratingly, reset completely. That's reset and in *pow!*
back to the BIOS startup. No panic, no crashdump, just a reset. This
appeared to happen most often when MiniportReset() was called. (As
to why MiniportReset() was being called, see problem three below.)
I thought maybe I had created some sort of horrible deadlock
condition in the process of adding the serialization, but after three
weeks, at least 6 different locking implementations and heroic efforts
to debug the spinlock code, the machine still kept resetting. Finally,
I started single stepping through the MiniportReset() routine in
the driver using the kernel debugger, and this ultimately led me to
the source of the problem.

One of the last things the Atheros MiniportReset() routine does is
call NdisReadPciSlotInformation() several times to inspect a portion
of the device's PCI config space. It reads the same chunk of config
space repeatedly, in rapid succession. Presumeably, it's polling
the hardware for some sort of event. The reset occurs partway through
this process. I discovered that when I single-stepped through this
portion of the routine, the reset didn't occur. So I inserted a 1
microsecond delay into the read loop in NdisReadPciSlotInformation().
Suddenly, the reset was gone!!

I'm still very puzzled by the whole thing. What I suspect is happening
is that reading the PCI config space so quickly is causing a severe
PCI bus error. My test system is a Sun w2100z dual Opteron system,
and the NIC is a miniPCI card mounted in a miniPCI-to-PCI carrier card,
plugged into a 100Mhz PCI slot. It's possible that this combination of
hardware causes a bus protocol violation in this scenario which leads
to a fatal machine check. This is pure speculation though. Really all I
know for sure is that inserting the delay makes the problem go away.
(To quote Homer Simpson: "I don't know how it works, but fire makes
it good!")

Problem number three: NdisAllocatePacket() needs to make sure to
initialize the npp_validcounts field in the 'private' section of
the NDIS_PACKET structure. The reason if_ndis was calling the
MiniportReset() routine in the first place is that packet transmits
were sometimes hanging. When sending a packet, an NDIS driver will
call NdisQueryPacket() to learn how many physical buffers the packet
resides in. NdisQueryPacket() is actually a macro, which traverses
the NDIS_BUFFER list attached to the NDIS_PACKET and stashes some
of the results in the 'private' section of the NDIS_PACKET. It also
sets the npp_validcounts field to TRUE To indicate that the results are
now valid. The problem is, now that if_ndis creates a pool of transmit
packets via NdisAllocatePacketPool(), it's important that each time
a new packet is allocated via NdisAllocatePacket() that validcounts
be initialized to FALSE. If it isn't, and a previously transmitted
NDIS_PACKET is pulled out of the pool, it may contain stale data
from a previous transmission which won't get updated by NdisQueryPacket().
This would cause the driver to miscompute the number of fragments
for a given packet, and botch the transmission.

Fixing these three problems seems to make the Atheros driver happy
on SMP, which hopefully means other serialized miniports will be
happy too.

And there was much rejoicing.

Other stuff fixed along the way:

- Modified ndis_thsuspend() to take a mutex as an argument. This
allows KeWaitForSingleObject() and KeWaitForMultipleObjects() to
avoid any possible race conditions with other routines that
use the dispatcher lock.

- Fixed KeCancelTimer() so that it returns the correct value for
'pending' according to the Microsoft documentation

- Modfied NdisGetSystemUpTime() to use ticks and hz rather than
calling nanouptime(). Also added comment that this routine wraps
after 49.7 days.

- Added macros for KeAcquireSpinLock()/KeReleaseSpinLock() to hide
all the MSCALL() goop.

- For x86, KeAcquireSpinLockRaiseToDpc() needs to be a separate
function. This is because it's supposed to be _stdcall on the x86
arch, whereas KeAcquireSpinLock() is supposed to be _fastcall.
On amd64, all routines use the same calling convention so we can
just map KeAcquireSpinLockRaiseToDpc() directly to KfAcquireSpinLock()
and it will work. (The _fastcall attribute is a no-op on amd64.)

- Implement and use IoInitializeDpcRequest() and IoRequestDpc() (they're
just macros) and use them for interrupt handling. This allows us to
move the ndis_intrtask() routine from if_ndis.c to kern_ndis.c.

- Fix the MmInitializeMdl() macro so that is uses sizeof(vm_offset_t)
when computing mdl_size instead of uint32_t, so that it matches the
MmSizeOfMdl() routine.

- Change a could of M_WAITOKs to M_NOWAITs in the unicode routines in

- Use the dispatcher lock a little more consistently in subr_ntoskrnl.c.

- Get rid of the "wait for link event" hack in ndis_init(). Now that
I fixed NdisReadPciSlotInformation(), it seems I don't need it anymore.
This should fix the witness panic a couple of people have reported.

- Use MSCALL1() when calling the MiniportHangCheck() function in
ndis_ticktask(). I accidentally missed this one when adding the
wrapping for amd64.
a72168b811cd0f0d5a830afea5d5aea2fd65d443 07-Mar-2005 wpaul <wpaul@FreeBSD.org> When you call MiniportInitialize() for an 802.11 driver, it will
at some point result in a status event being triggered (it should
be a link down event: the Microsoft driver design guide says you
should generate one when the NIC is initialized). Some drivers
generate the event during MiniportInitialize(), such that by the
time MiniportInitialize() completes, the NIC is ready to go. But
some drivers, in particular the ones for Atheros wireless NICs,
don't generate the event until after a device interrupt occurs
at some point after MiniportInitialize() has completed.

The gotcha is that you have to wait until the link status event
occurs one way or the other before you try to fiddle with any
settings (ssid, channel, etc...). For the drivers that set the
event sycnhronously this isn't a problem, but for the others
we have to pause after calling ndis_init_nic() and wait for the event
to arrive before continuing. Failing to wait can cause big trouble:
on my SMP system, calling ndis_setstate_80211() after ndis_init_nic()
completes, but _before_ the link event arrives, will lock up or
reset the system.

What we do now is check to see if a link event arrived while
ndis_init_nic() was running, and if it didn't we msleep() until
it does.

Along the way, I discovered a few other problems:

- Defered procedure calls run at PASSIVE_LEVEL, not DISPATCH_LEVEL.
ntoskrnl_run_dpc() has been fixed accordingly. (I read the documentation

- Similarly, the NDIS interrupt handler, which is essentially a
DPC, also doesn't need to run at DISPATCH_LEVEL. ndis_intrtask()
has been fixed accordingly.

- MiniportQueryInformation() and MiniportSetInformation() run at
DISPATCH_LEVEL, and each request must complete before another
can be submitted. ndis_get_info() and ndis_set_info() have been
fixed accordingly.

- Turned the sleep lock that guards the NDIS thread job list into
a spin lock. We never do anything with this lock held except manage
the job list (no other locks are held), so it's safe to do this,
and it's possible that ndis_sched() and ndis_unsched() can be
called from DISPATCH_LEVEL, so using a sleep lock here is
semantically incorrect. Also updated subr_witness.c to add the
lock to the order list.
15a925bf93f66957108aef1fb3c1092808a403aa 26-Feb-2005 wpaul <wpaul@FreeBSD.org> MDLs are supposed to be variable size (they include an array of pages
that describe a buffer of variable size). The problem is, allocating
MDLs off the heap is slow, and it can happen that drivers will allocate
lots and lots of lots of MDLs as they run.

As a compromise, we now do the following: we pre-allocate a zone for
MDLs big enough to describe any buffer with 16 or less pages. If
IoAllocateMdl() needs a MDL for a buffer with 16 or less pages, we'll
allocate it from the zone. Otherwise, we allocate it from the heap.
MDLs allocate from the zone have a flag set in their mdl_flags field.
When the MDL is released, IoMdlFree() will uma_zfree() the MDL if
it has the MDL_ZONE_ALLOCED flag set, otherwise it will release it
to the heap.

The assumption is that 16 pages is a "big number" and we will rarely
need MDLs larger than that.

- Moved the ndis_buffer zone to subr_ntoskrnl.c from kern_ndis.c
and named it mdl_zone.

- Modified IoAllocateMdl() and IoFreeMdl() to use uma_zalloc() and
uma_zfree() if necessary.

- Made ndis_mtop() use IoAllocateMdl() instead of calling uma_zalloc()

Inspired by: discussion with Giridhar Pemmasani
64968e6acf5ff861688b6949c16607a5852492d4 25-Feb-2005 wpaul <wpaul@FreeBSD.org> Fix a couple of callback instances that should have been wrapped with

Add definition for STATUS_PENDING error code.
7a502b730915fdd3f3392404b7084b4457a62e20 25-Feb-2005 wpaul <wpaul@FreeBSD.org> Compute the right length to use with bzero() when initializing an IRP
in IoInitializeIrp() (must use IoSizeOfIrp() to account for the stack
6e74cf6e34565f42c3fe52a8caf126f7048941d4 24-Feb-2005 wpaul <wpaul@FreeBSD.org> Couple of lessons learned during USB driver testing:

- In kern_ndis.c:ndis_unload_driver(), test that ndis_block->nmb_rlist
is not NULL before trying to free() it.

- In subr_pe.c:pe_get_import_descriptor(), do a case-insensitive
match on the import module name. Most drivers I have encountered
link against "ntoskrnl.exe" but the ASIX USB ethernet driver I'm
testing with wants "NTOSKRNL.EXE."

- In subr_ntoskrnl.c:IoAllocateIrp(), return a pointer to the IRP
instead of NULL. (Stub code leftover.)

- Also in subr_ntoskrnl.c, add ExAllocatePoolWithTag() and ExFreePool()
to the function table list so they'll get exported to drivers properly.
954c02c21fd1c9c5cb4a8e8c3db163eb83103f72 23-Feb-2005 wpaul <wpaul@FreeBSD.org> Implement IoCancelIrp(), IoAcquireCancelSpinLock(), IoReleaseCancelSpinLock()
and a machine-independent though inefficient InterlockedExchange().
In Windows, InterlockedExchange() appears to be implemented in header
files via inline assembly. I would prefer using an atomic.h macro for
this, but there doesn't seem to be one that just does a plain old
atomic exchange (as opposed to compare and exchange). Also implement
IoSetCancelRoutine(), which is just a macro that uses InterlockedExchange().

Fill in IoBuildSynchronousFsdRequest(), IoBuildAsynchronousFsdRequest()
and IoBuildDeviceIoControlRequest() so that they do something useful,
and add a bunch of #defines to ntoskrnl_var.h to help make these work.
These may require some tweaks later.
a372ba85cee8186936a67b01506b82c45df2adfe 16-Feb-2005 wpaul <wpaul@FreeBSD.org> KeAcquireSpinLockRaiseToDpc() and KeReleaseSpinLock() are (at least
for now) exactly the same as KfAcquireSpinLock() and KfReleaseSpinLock().
I implemented the former as small routines in subr_ntoskrnl.c that just
turned around and invoked the latter. But I don't really need the wrapper
routines: I can just create an entries in the ntoskrnl func table that
map KeAcquireSpinLockRaiseToDpc() and KeReleaseSpinLock() to
KfAcquireSpinLock() and KfReleaseSpinLock() directly. This means
the stubs can go away.
07b632956a99a773db5488fdd2ffd5f209d38dea 16-Feb-2005 wpaul <wpaul@FreeBSD.org> Add support for Windows/x86-64 binaries to Project Evil.
Ville-Pertti Keinonen (will at exomi dot comohmygodnospampleasekthx)
deserves a big thanks for submitting initial patches to make it
work. I have mangled his contributions appropriately.

The main gotcha with Windows/x86-64 is that Microsoft uses a different
calling convention than everyone else. The standard ABI requires using
6 registers for argument passing, with other arguments on the stack.
Microsoft uses only 4 registers, and requires the caller to leave room
on the stack for the register arguments incase the callee needs to
spill them. Unlike x86, where Microsoft uses a mix of _cdecl, _stdcall
and _fastcall, all routines on Windows/x86-64 uses the same convention.
This unfortunately means that all the functions we export to the
driver require an intermediate translation wrapper. Similarly, we have
to wrap all calls back into the driver binary itself.

The original patches provided macros to wrap every single routine at
compile time, providing a secondary jump table with a customized
wrapper for each exported routine. I decided to use a different approach:
the call wrapper for each function is created from a template at
runtime, and the routine to jump to is patched into the wrapper as
it is created. The subr_pe module has been modified to patch in the
wrapped function instead of the original. (On x86, the wrapping
routine is a no-op.)

There are some minor API differences that had to be accounted for:

- KeAcquireSpinLock() is a real function on amd64, not a macro wrapper
around KfAcquireSpinLock()
- NdisFreeBuffer() is actually IoFreeMdl(). I had to change the whole
NDIS_BUFFER API a bit to accomodate this.

Bugs fixed along the way:
- IoAllocateMdl() always returned NULL
- kern_windrv.c:windrv_unload() wasn't releasing private driver object
extensions correctly (found thanks to memguard)

This has only been tested with the driver for the Broadcom 802.11g
chipset, which was the only Windows/x86-64 driver I could find.
df89b626983fe6b8b3366ad0147e35b1a6a8fd37 08-Feb-2005 wpaul <wpaul@FreeBSD.org> Next step on the road to IRPs: create and use an imitation of the
Windows DRIVER_OBJECT and DEVICE_OBJECT mechanism so that we can
simulate driver stacking.

In Windows, each loaded driver image is attached to a DRIVER_OBJECT
structure. Windows uses the registry to match up a given vendor/device
ID combination with a corresponding DRIVER_OBJECT. When a driver image
is first loaded, its DriverEntry() routine is invoked, which sets up
the AddDevice() function pointer in the DRIVER_OBJECT and creates
a dispatch table (based on IRP major codes). When a Windows bus driver
detects a new device, it creates a Physical Device Object (PDO) for
it. This is a DEVICE_OBJECT structure, with semantics analagous to
that of a device_t in FreeBSD. The Windows PNP manager will invoke
the driver's AddDevice() function and pass it pointers to the DRIVER_OBJECT
and the PDO.

The AddDevice() function then creates a new DRIVER_OBJECT structure of
its own. This is known as the Functional Device Object (FDO) and
corresponds roughly to a private softc instance. The driver uses
IoAttachDeviceToDeviceStack() to add this device object to the
driver stack for this PDO. Subsequent drivers (called filter drivers
in Windows-speak) can be loaded which add themselves to the stack.
When someone issues an IRP to a device, it travel along the stack
passing through several possible filter drivers until it reaches
the functional driver (which actually knows how to talk to the hardware)
at which point it will be completed. This is how Windows achieves
driver layering.

Project Evil now simulates most of this. if_ndis now has a modevent
handler which will use MOD_LOAD and MOD_UNLOAD events to drive the
creation and destruction of DRIVER_OBJECTs. (The load event also
does the relocation/dynalinking of the image.) We don't have a registry,
so the DRIVER_OBJECTS are stored in a linked list for now. Eventually,
the list entry will contain the vendor/device ID list extracted from
the .INF file. When ndis_probe() is called and detectes a supported
device, it will create a PDO for the device instance and attach it
to the DRIVER_OBJECT just as in Windows. ndis_attach() will then call
our NdisAddDevice() handler to create the FDO. The NDIS miniport block
is now a device extension hung off the FDO, just as it is in Windows.
The miniport characteristics table is now an extension hung off the
DRIVER_OBJECT as well (the characteristics are the same for all devices
handled by a given driver, so they don't need to be per-instance.)
We also do an IoAttachDeviceToDeviceStack() to put the FDO on the
stack for the PDO. There are a couple of fake bus drivers created
for the PCI and pccard buses. Eventually, there will be one for USB,
which will actually accept USB IRP.s

Things should still work just as before, only now we do things in
the proper order and maintain the correct framework to support passing
IRPs between drivers.

Various changes:

- corrected the comments about IRQL handling in subr_hal.c to more
accurately reflect reality
- update ndiscvt to make the drv_data symbol in ndis_driver_data.h a
global so that if_ndis_pci.o and/or if_ndis_pccard.o can see it.
- Obtain the softc pointer from the miniport block by referencing
the PDO rather than a private pointer of our own (nmb_ifp is no
longer used)
- implement IoAttachDeviceToDeviceStack(), IoDetachDevice(),
IoGetAttachedDevice(), IoAllocateDriverObjectExtension(),
IoGetDriverObjectExtension(), IoCreateDevice(), IoDeleteDevice(),
IoAllocateIrp(), IoReuseIrp(), IoMakeAssociatedIrp(), IoFreeIrp(),
- fix a few mistakes in the driver_object and device_object definitions
- add a new module, kern_windrv.c, to handle the driver registration
and relocation/dynalinkign duties (which don't really belong in
- made ndis_block and ndis_chars in the ndis_softc stucture pointers
and modified all references to it
- fixed NdisMRegisterMiniport() and NdisInitializeWrapper() so they
work correctly with the new driver_object mechanism
- changed ndis_attach() to call NdisAddDevice() instead of ndis_load_driver()
(which is now deprecated)
- used ExAllocatePoolWithTag()/ExFreePool() in lookaside list routines
instead of kludged up alloc/free routines
- added kern_windrv.c to sys/modules/ndis/Makefile and files.i386.
e00c1df9076d2ce0230549efdb48862177e730e2 25-Jan-2005 wpaul <wpaul@FreeBSD.org> Apparently, the Intel icc compiler doesn't like it when you use
attributes in casts (i.e. foo = (__stdcall sometype)bar). This only
happens in two places where we need to set up function pointers, so
work around the problem with some void pointer magic.
361515a4123365d5eb5137c5f6a99d0db50f2532 24-Jan-2005 wpaul <wpaul@FreeBSD.org> Begin the first phase of trying to add IRP support (and ultimately
USB device support):

- Convert all of my locally chosen function names to their actual
Windows equivalents, where applicable. This is a big no-op change
since it doesn't affect functionality, but it helps avoid a bit
of confusion (it's now a lot easier to see which functions are
emulated Windows API routines and which are just locally defined).

- Turn ndis_buffer into an mdl, like it should have been. The structure
is the same, but now it belongs to the subr_ntoskrnl module.

- Implement a bunch of MDL handling macros from Windows and use them where

- Correct the implementation of IoFreeMdl().

- Properly implement IoAllocateMdl() and MmBuildMdlForNonPagedPool().

- Add the definitions for struct irp and struct driver_object.

- Add IMPORT_FUNC() and IMPORT_FUNC_MAP() macros to make formatting
the module function tables a little cleaner. (Should also help
with AMD64 support later on.)

- Fix if_ndis.c to use KeRaiseIrql() and KeLowerIrql() instead of
the previous calls to hal_raise_irql() and hal_lower_irql() which
have been renamed.

The function renaming generated a lot of churn here, but there should
be very little operational effect.
2fe7b09cb198e42356fd30dbc005daff0809ff0c 14-Jan-2005 wpaul <wpaul@FreeBSD.org> Fix a problem reported by Pierre Beyssac. Sometinmes when ndis_get_info()
calls MiniportQueryInformation(), it will return NDIS_STATUS_PENDING.
When this happens, ndis_get_info() will sleep waiting for a completion
event. If two threads call ndis_get_info() and both end up having to
sleep, they will both end up waiting on the same wait channel, which
can cause a panic in sleepq_add() if INVARIANTS are turned on.

Fix this by having ndis_get_info() use a common mutex rather than
using the process mutex with PROC_LOCK(). Also do the same for
ndis_set_info(). Note that Pierre's original patch also made ndis_thsuspend()
use the new mutex, but ndis_thsuspend() shouldn't need this since
it will make each thread that calls it sleep on a unique wait channel.

Also, it occured to me that we probably don't want to enter
MiniportQueryInformation() or MiniportSetInformation() from more
than one thread at any given time, so now we acquire a Windows
spinlock before calling either of them. The Microsoft documentation
says that MiniportQueryInformation() and MiniportSetInformation()
are called at DISPATCH_LEVEL, and previously we would call
KeRaiseIrql() to set the IRQL to DISPATCH_LEVEL before entering
either routine, but this only guarantees mutual exclusion on
uniprocessor machines. To make it SMP safe, we need to use a real
spinlock. For now, I'm abusing the spinlock embedded in the
NDIS_MINIPORT_BLOCK structure for this purpose. (This may need to be
applied to some of the other routines in kern_ndis.c at a later date.)

Export ntoskrnl_init_lock() (KeInitializeSpinlock()) from subr_ntoskrnl.c
since we need to use in in kern_ndis.c, and since it's technically part
of the Windows kernel DDK API along with the other spinlock routines. Use
it in subr_ndis.c too rather than frobbing the spinlock directly.
362fcfc1e268b4cff39cae1448f01c51def69091 05-Jan-2005 imp <imp@FreeBSD.org> Start each of the license/copyright comments with /*-
94e51111dcbcaf37886960c09a9c77394e708d10 17-Sep-2004 bms <bms@FreeBSD.org> Fix compiler warnings, when __stdcall is #defined, by adding explicit casts.
These normally only manifest if the ndis compat module is statically
compiled into a kernel image by way of 'options NDISAPI'.

Submitted by: Dmitri Nikulin
Approved by: wpaul
PR: kern/71449
MFC after: 1 week
5b5d2c54bc844d6f80b41f02bf70a9f3a49e54ee 16-Aug-2004 wpaul <wpaul@FreeBSD.org> The Texas Instruments ACX111 driver wants srand(), so provide it.
f7237cd69681ed69392d6f7fb7a0f507980b0673 04-Aug-2004 wpaul <wpaul@FreeBSD.org> More minor cleanups and one small bug fix:

- In ntoskrnl_var.h, I had defined compat macros for
ntoskrnl_acquire_spinlock() and ntoskrnl_release_spinlock() but
never used them. This is fortunate since they were stale. Fix them
to work properly. (In Windows/x86 KeAcquireSpinLock() is a macro that
calls KefAcquireSpinLock(), which lives in HAL.dll. To imitate this,
ntoskrnl_acquire_spinlock() is just a macro that calls hal_lock(),
which lives in subr_hal.o.)

- Add macros for ntoskrnl_raise_irql() and ntoskrnl_lower_irql() that
call hal_raise_irql() and hal_lower_irql().

- Use these macros in kern_ndis.c, subr_ndis.c and subr_ntoskrnl.c.

- Along the way, I realised subr_ndis.c:ndis_lock() was not calling
hal_lock() correctly (it was using the FASTCALL2() wrapper when
in reality this routine is FASTCALL1()). Using the
ntoskrnl_acquire_spinlock() fixes this. Not sure if this actually
caused any bugs since hal_lock() would have just ignored what
was in %edx, but it was still bogus.

This hides many of the uses of the FASTCALLx() macros which makes the
code a little cleaner. Should not have any effect on generated object
code, other than the one fix in ndis_lock().
b9b3caf965335247a6b02d871301c0e4c4bb87f6 01-Aug-2004 wpaul <wpaul@FreeBSD.org> Big mess 'o changes:

- Give ndiscvt(8) the ability to process a .SYS file directly into
a .o file so that we don't have to emit big messy char arrays into
the ndis_driver_data.h file. This behavior is currently optional, but
may become the default some day.

- Give ndiscvt(8) the ability to turn arbitrary files into .ko files
so that they can be pre-loaded or kldloaded. (Both this and the
previous change involve using objcopy(1)).

- Give NdisOpenFile() the ability to 'read' files out of kernel memory
that have been kldloaded or pre-loaded, and disallow the use of
the normal vn_open() file opening method during bootstrap (when no
filesystems have been mounted yet). Some people have reported that
kldloading if_ndis.ko works fine when the system is running multiuser
but causes a panic when the modile is pre-loaded by /boot/loader. This
happens with drivers that need to use NdisOpenFile() to access
external files (i.e. firmware images). NdisOpenFile() won't work
during kernel bootstrapping because no filesystems have been mounted.
To get around this, you can now do the following:

o Say you have a firmware file called firmware.img
o Do: ndiscvt -f firmware.img -- this creates firmware.img.ko
o Put the firmware.img.ko in /boot/kernel
o add firmware.img_load="YES" in /boot/loader.conf
o add if_ndis_load="YES" and ndis_load="YES" as well

Now the loader will suck the additional file into memory as a .ko. The
phony .ko has two symbols in it: filename_start and filename_end, which
are generated by objcopy(1). ndis_open_file() will traverse each module
in the module list looking for these symbols and, if it finds them, it'll
use them to generate the file mapping address and length values that
the caller of NdisOpenFile() wants.

As a bonus, this will even work if the file has been statically linked
into the kernel itself, since the "kernel" module is searched too.
(ndiscvt(8) will generate both filename.o and filename.ko for you).

- Modify the mechanism used to provide make-pretend FASTCALL support.
Rather than using inline assembly to yank the first two arguments
out of %ecx and %edx, we now use the __regparm__(3) attribute (and
the __stdcall__ attribute) and use some macro magic to re-order
the arguments and provide dummy arguments as needed so that the
arguments passed in registers end up in the right place. Change
taken from DragonflyBSD version of the NDISulator.
ab2a462550eaef118bef70261ce42559f1120ca4 20-Jul-2004 wpaul <wpaul@FreeBSD.org> *sigh* Fix source code compatibility with 5.2.1-RELEASE _again_.
(Make kdb stuff conditional.)
7fd8e711255acc5a2519a913d14f19fbd62c5637 10-Jul-2004 marcel <marcel@FreeBSD.org> Update for the KDB framework:
o Call kdb_enter() instead of Debugger().

While here, remove a redundant return.
923c7351dd3852aeb1bf5213b6777eb4a86499e5 07-Jun-2004 wpaul <wpaul@FreeBSD.org> Add another 5.2.1 source compatibility tweak: acquire Giant before calling
kthread_exit() if FreeBSD_version is old enough.
a7f0f62fc064d21a3552570d4df9d35133baad13 30-Apr-2004 wpaul <wpaul@FreeBSD.org> Small timer cleanups:

- Use the dh_inserted member of the dispatch header in the Windows
timer structure to indicate that the timer has been "inserted into
the timer queue" (i.e. armed via timeout()). Use this as the value
to return to the caller in KeCancelTimer(). Previously, I was using
callout_pending(), but you can't use that with timeout()/untimeout()
without creating a potential race condition.

- Make ntoskrnl_init_timer() just a wrapper around ntoskrnl_init_timer_ex()
(reduces some code duplication).

- Drop Giant when entering if_ndis.c:ndis_tick() and
subr_ntorkrnl.c:ntoskrnl_timercall(). At the moment, I'm forced to
use system callwheel via timeout()/untimeout() to handle timers rather
than the callout API (struct callout is too big to fit inside the
Windows struct KTIMER, so I'm kind of hosed). Unfortunately, all
the callouts in the callwhere are not marked as MPSAFE, so when
one of them fires, it implicitly acquires Giant before invoking the
callback routine (and releases it when it returns). I don't need to
hold Giant, but there's no way to stop the callout code from acquiring
it as long as I'm using timeout()/untimeout(), so for now we cheat
by just dropping Giant right away (and re-acquiring it right before
the routine returns so keep the callout code happy). At some point,
I will need to solve this better, but for now this should be a suitable
a98d8ced5454e8e836a2d65fffe51f2f7475b313 18-Apr-2004 wpaul <wpaul@FreeBSD.org> In ntoskrnl_unlock_dpc(), use atomic_store instead of atomic_cmpset
to give up the spinlock.

Suggested by: bde
1ea56deba6d80d9814e14d9824afaabbd44e2083 16-Apr-2004 wpaul <wpaul@FreeBSD.org> - Use memory barrier with atomic operations in ntoskrnl_lock_dpc() and
- hal_raise_irql(), hal_lower_irql() and hal_irql() didn't work right
on SMP (priority inheritance makes things... interesting). For now,
(everything else). Tested on a dual PIII box.
- Use ndis_thsuspend() in ndis_sleep() instead of tsleep(). (I added
ndis_thsuspend() and ndis_thresume() to replace kthread_suspend()
and kthread_resume(); the former will preserve a thread's priority
when it wakes up, the latter will not.)
- Change use of tsleep() in ndis_stop_thread() to prevent priority
change on wakeup.
9765d24df650a8593a1d8dbd170e1f17b4bcb60f 14-Apr-2004 wpaul <wpaul@FreeBSD.org> 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
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

- 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

- 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.
b41d925167717d0521d046c8ed82094f3d546f53 27-Mar-2004 wpaul <wpaul@FreeBSD.org> Apparently, some atheros drivers want rand(), so implement it (in terms
of random()).

Requested by: juli
Bribe offered: tacos
57efe0d11e10072b9cc7f8b04f3de0bb7e2dd356 25-Mar-2004 wpaul <wpaul@FreeBSD.org> - In kern_ndis.c, implement ndis_unsched(), the complement to ndis_sched(),
which pulls a job off a thread work queue (assuming it hasn't run yet).
This is needed for KeRemoveQueueDpc().

- In subr_ntoskrnl.c, implement KeInsertQueueDpc() and KeRemoveQueueDpc(),
to go with KeInitializeDpc() to round out the API. Also change the
KeTimer implementation to use this API instead of the private
timer callout scheduler. Functionality of the timer API remains
unchanged, but we get a couple new Windows kernel API routines and
more closely imitate the way thing works in Windows. (As of yet
I haven't encountered any drivers that use KeInsertQueueDpc() or
KeRemoveQueueDpc(), but it doesn't hurt to have them.)
0cae7408ddc80357dafc03d961848402f7ff8775 22-Mar-2004 wpaul <wpaul@FreeBSD.org> Remove another case of grabbing Giant before doing a kthread_exit()
which is now no longer needed.
e7b058478d636902088f5a1b282ed707c6b8af70 22-Mar-2004 wpaul <wpaul@FreeBSD.org> The Intel 2200BG NDIS driver does an alloca() of about 5000 bytes
when it associates with a net. Because FreeBSD's kstack size is only
2 pages by default, this blows the stack and causes a double fault.

To deal with this, we now create all our kthreads with 8 stack pages.
Also, we now run all timer callouts in the ndis swi thread (since
they would otherwise run in the clock ithread, whose stack is too
small). It happens that the alloca() in this case was occuring within
the interrupt handler, which was already running in the ndis swi
thread, but I want to deal with the callouts too just to be extra

NOTE: this will only work if you update vm_machdep.c with the change
I just committed. If you don't include this fix, setting the number
of stack pages with kthread_create() has essentially no effect.
8feaa1f4505bcdc10cab48f06ef55675e2d6e324 20-Mar-2004 wpaul <wpaul@FreeBSD.org> - 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.
5aa1390e6194fb0a1bbed52f0468cec21e7c2dab 15-Mar-2004 wpaul <wpaul@FreeBSD.org> Add vectors for _snprintf() and _vsnprintf() (redirected straight to
snprintf() and vsnprintf() in FreeBSD kernel land).

This is needed by the Intel Centrino 2200BG driver. Unfortunately, this
driver still doesn't work right with Project Evil even with this tweak,
but I'm unable to diagnose the problem since I don't have access to a
sample card.
dab75fac6b16faec6e60df4a6fcd6a2e2cdd4515 10-Mar-2004 wpaul <wpaul@FreeBSD.org> 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

- 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
f7976fadc05b3d03706b33163ca71bf8f902a35b 04-Mar-2004 wpaul <wpaul@FreeBSD.org> - Some older Atheros drivers want KeInitializeTimer(), so implement it,
along with KeInitializeTimerEx(), KeSetTimer(), KeSetTimerEx(),
KeCancelTimer(), KeReadStateTimer() and KeInitializeDpc(). I don't
know for certain that these will make the Atheros driver happy since
I don't have the card/driver combo needed to test it, but these are
fairly independent so they shouldn't break anything else.

- Debugger() is present even in kernels without options DDB, so no
conditional compilation is necessary (pointed out by bde).

- Remove the extra km_acquirecnt member that I added to struct kmutant
and embed it within an unused portion of the structure instead, so that
we don't make the structure larger than it's defined to be in Windows.
I don't know what crack I was smoking when I decided it was ok to do
this, but it's worn off now.
3ca539236dcf413518191a1d538f5f13738e48f1 04-Mar-2004 wpaul <wpaul@FreeBSD.org> 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.
753cd4eacb825efbc5a6467dff1b2ba0f4748a1a 03-Mar-2004 wpaul <wpaul@FreeBSD.org> Add proper support for DbgPrint(): only print messages if bootverbose
is set, since some drivers with debug info can be very chatty.

Also implement DbgBreakPoint(), which is the Windows equivalent of
Debugger(). Unfortunately, this forces subr_ntoskrnl.c to include
427370d7d184c585bca13df8d6feaa7fb2e6f01a 17-Feb-2004 wpaul <wpaul@FreeBSD.org> Add vector for memmove() (currently aliased to memcpy()) a implement
1e2ef501f0d5f552cae8e4514235ae939d09a69d 16-Feb-2004 wpaul <wpaul@FreeBSD.org> More cleanups/fixes for the AMD Am1771 driver:

- When adding new waiting threads to the waitlist for an object,
use INSERT_LIST_TAIL() instead of INSERT_LIST_HEAD() so that new
waiters go at the end of the list instead of the beginning. When we
wake up a synchronization object, only the first waiter is awakened,
and this needs to be the first thread that actually waited on the object.

- Correct missing semicolon in INSERT_LIST_TAIL() macro.

- Implement lookaside lists correctly. Note that the Am1771 driver
uses lookaside lists to manage shared memory (i.e. DMAable) buffers
by specifying its own alloc and free routines. The Microsoft documentation
says you should avoid doing this, but apparently this did not deter
the developers at AMD from doing it anyway.

With these changes (which are the result of two straight days of almost
non-stop debugging), I think I finally have the object/thread handling
semantics implemented correctly. The Am1771 driver no longer crashes
unexpectedly during association or bringing the interface up.
d3ac9e6362fb681e80b72672bba2fb88c344d9e4 11-Feb-2004 wpaul <wpaul@FreeBSD.org> Correct instance of *timeout that should have been timeout.

Noticed by: mlaier
fe7c8eefc3547f53401867e00dfc83a66bb130b7 07-Feb-2004 wpaul <wpaul@FreeBSD.org> Add a whole bunch of new stuff to make the driver for the AMD Am1771/Am1772
802.11b chipset work. This chip is present on the SMC2602W version 3
NIC, which is what was used for testing. This driver creates kernel
threads (12 of them!) for various purposes, and required the following


and several more. Also, this driver abuses the fact that NDIS events
and timers are actually Windows events and timers, and uses NDIS events
with KeWaitForSingleObject(). The NDIS event routines have been rewritten
to interface with the ntoskrnl module. Many routines with incorrect
prototypes have been cleaned up.

Also, this driver puts jobs on the NDIS taskqueue (via NdisScheduleWorkItem())
which block on events, and this interferes with the operation of
NdisMAllocateSharedMemoryAsync(), which was also being put on the
NDIS taskqueue. To avoid the deadlock, NdisMAllocateSharedMemoryAsync()
is now performed in the NDIS SWI thread instead.

There's still room for some cleanups here, and I really should implement
KeInitializeTimer() and friends.
acff10ceaccffd3e88bbb7bd07150b994577dccb 19-Jan-2004 wpaul <wpaul@FreeBSD.org> Implement IofCompleteRequest() and IoIsWdmVersionAvailable().
Correct IofCallDriver(): it's fastcall, not stdcall.
Add vector to vsprintf().
e3b2b97f35417363c9f559e8436a2d7986e91405 19-Jan-2004 wpaul <wpaul@FreeBSD.org> Implement atoi() and atol(). Some drivers appear to need these. Note
that like most C library routines, these appear to be _cdecl in Windows.
dfae368ae89abaf08547d94099bb050de06b12f7 15-Jan-2004 wpaul <wpaul@FreeBSD.org> The definition for __stdcall logically belongs in pe_var.h, but
the definitions for NDIS_BUS_SPACE_IO and NDIS_BUS_SPACE_MEM logically
belong in hal_var.h. At least, that's my story, and I'm sticking to it.

Also, remove definition of __stdcall from if_ndis.c now that it's pulled
in from pe_var.h.
32b034d034b5eb777a4e1f90afab9e5da09082db 15-Jan-2004 obrien <obrien@FreeBSD.org> Create NDIS_BUS_SPACE_{IO,MEM} to abstract MD BUS_SPACE macros.
Provide appropriate definitions for i386 and AMD64.
db0a9fc4de11e1379d9f2ca83f0208e6fa37e91d 13-Jan-2004 obrien <obrien@FreeBSD.org> AMD64 has a single MS-Win calling convention, so provide an empty __stdcall.
Centralize the definition to make it easier to change.
7a17945656dacf9dea3bbe3cd2ec7df035ceaea4 13-Jan-2004 wpaul <wpaul@FreeBSD.org> Implement some more unicode handling routines. This will hopefully bring
us closer to being able to run the Intel PRO/Wireless 5000 driver.
2c0e413ccc02aa53f20af2ca9655c8fcdd1010ed 12-Jan-2004 wpaul <wpaul@FreeBSD.org> Ugh. Last commit went horribly wrong. Back out changes to subr_ntoskrnl.c,
make sure if_ndis.c really gets checked in this time.
377a4756cda494302db31c4722b9306848499b34 12-Jan-2004 wpaul <wpaul@FreeBSD.org> In if_ndis.c:ndis_intr(), be a bit more intelligent about squelching
unexpected interrupts. If an interrupt is triggered and we're not
finished initializing yet, bail. If we have finished initializing,
but IFF_UP isn't set yet, drain the interrupt with ndis_intr() or
ndis_disable_intr() as appropriate, then return _without_ scheduling

In kern_ndis.c:ndis_load_driver() only relocate/dynalink a given driver
image once. Trying to relocate an image that's already been relocated
will trash the image. We poison a part of the image header that we
don't otherwise need with a magic value to indicate it's already been
fixed up. This fixes the case where there are multiple units of the
same kind of device.
fcdf650572f5a3a8136abc088d10d11b87cfee2b 12-Jan-2004 wpaul <wpaul@FreeBSD.org> Merge in some changes submitted by Brian Feldman. Among other things,
these add support for listing BSSIDs via wicontrol -l. I added code
to call OID_802_11_BSSID_LIST_SCAN to allow scanning for any nearby
wirelsss nets.

Convert from using individual mutexes to a mutex pool, created in
subr_ndis.c. This deals with the problem of drivers creating locks
in their DriverEntry() routines which might get trashed later.

Put some messages under IFF_DEBUG.
53e00280699a62261ce2ada0cd5d5c55d51a2d26 07-Jan-2004 wpaul <wpaul@FreeBSD.org> Correct and simplify the implementation of RtlEqualUnicodeString().
67bfe86083a41c907ae64ed3fe8302aa556d4978 07-Jan-2004 wpaul <wpaul@FreeBSD.org> Use atomic ops for the interlocked increment and decrement routines
in subr_ndis and subr_ntoskrnl. This is faster and avoids potential
LOR whinage from witness (an LOR couldn't happen with the old code
since the interlocked inc/dec routines could not sleep with a lock
held, but this will keep witness happy and it's more efficient
anyway. I think.)
7452e76589c3544aeda69ca97dfcbd139dc08c09 06-Jan-2004 wpaul <wpaul@FreeBSD.org> - Add pe_get_message() and pe_get_messagetable() for processing
the RT_MESSAGETABLE resources that some driver binaries have.
This allows us to print error messages in ndis_syslog().

- Correct the implementation of InterlockedIncrement() and
InterlockedDecrement() -- they return uint32_t, not void.

- Correct the declarations of the 64-bit arithmetic shift
routines in subr_ntoskrnl.c (_allshr, allshl, etc...). These
do not follow the _stdcall convention: instead, they appear
to be __attribute__((regparm(3)).

- Change the implementation of KeInitializeSpinLock(). There is
no complementary KeFreeSpinLock() function, so creating a new
mutex on each call to KeInitializeSpinLock() leaks resources
when a driver is unloaded. For now, KeInitializeSpinLock()
returns a handle to the ntoskrnl interlock mutex.

- Use a driver's MiniportDisableInterrupt() and MiniportEnableInterrupt()
routines if they exist. I'm not sure if I'm doing this right
yet, but at the very least this shouldn't break any currently
working drivers, and it makes the Intel PRO/1000 driver work.

- In ndis_register_intr(), save some state that might be needed
later, and save a pointer to the driver's interrupt structure
in the ndis_miniport_block.

- Save a pointer to the driver image for use by ndis_syslog()
when it calls pe_get_message().
1319a94ada775ef8892c13f3ef70a121fc3ea151 04-Jan-2004 wpaul <wpaul@FreeBSD.org> Implement NdisScheduleWorkItem() and RtlCompareMemory().

Also, call the libinit and libfini routines from the modevent
handler in kern_ndis.c. This simplifies the initialization a little.
a43e13682e205a5b9215890c7fd108fc0233c385 03-Jan-2004 wpaul <wpaul@FreeBSD.org> Tweak ndiscvt to support yet another flavor of .INF files (look for
the NTx86 section decoration).

subr_ndis.c: correct the behavior of ndis_query_resources(): if the
caller doesn't provide enough space to return the resources, tell it
how much it needs to provide and return an error.

subr_hal.c & subr_ntoskrnl.c: implement/stub a bunch of new routines;





Lastly, correct spelling of "_aullshr" in the ntoskrnl functable.
b56a5ed44ae3babdfb15e99f87f9c85eaf3b2115 31-Dec-2003 wpaul <wpaul@FreeBSD.org> - subr_ntoskrnl.c: improve the _fastcall hack based on suggestions from
peter and jhb: use __volatile__ to prevent gcc from possibly reordering
code, use a null inline instruction instead of a no-op movl (I would
have done this myself if I knew it was allowed) and combine two register
assignments into a single asm statement.
- if_ndis.c: set the NDIS_STATUS_PENDING flag on all outgoing packets
in ndis_start(), make the resource allocation code a little smarter
about how it selects the altmem range, correct a lock order reversal
in ndis_tick().
385e9eaf78bb9aa940e8287c1fcf82fc01a1c958 25-Dec-2003 wpaul <wpaul@FreeBSD.org> - Add stubs for Ndis*File() functions
- Fix ndis_time().
- Implement NdisGetSystemUpTime().
- Implement RtlCopyUnicodeString() and RtlUnicodeStringToAnsiString().
- In ndis_getstate_80211(), use sc->ndis_link to determine connect

Submitted by: Brian Feldman <green@freebsd.org>
1883e811f747fa47da2d3be5d1a386f016b99e57 13-Dec-2003 wpaul <wpaul@FreeBSD.org> 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()

- add missing member to the general_lookaside struct (gl_listentry)

- 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.
27ada5499823ed0f050b3303fd142aa9877e464c 12-Dec-2003 wpaul <wpaul@FreeBSD.org> 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(),

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.
7e1ac581496c0d5c9235e96f48e6664b7783122e 11-Dec-2003 wpaul <wpaul@FreeBSD.org> 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
- 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