cvs commit: src/sys/compat/ndis hal_var.h kern_ndis.c ndis_var.h ntoskrnl_var.h pe_var.h subr_hal.c subr_ndis.c subr_ntoskrnl.c src/sys/dev/if_ndis if_ndis.c if_ndisvar.h

Bill Paul wpaul at
Wed Apr 14 00:48:07 PDT 2004

wpaul       2004/04/14 00:48:03 PDT

  FreeBSD src repository

  Modified files:
    sys/compat/ndis      hal_var.h kern_ndis.c ndis_var.h 
                         ntoskrnl_var.h pe_var.h subr_hal.c 
                         subr_ndis.c subr_ntoskrnl.c 
    sys/dev/if_ndis      if_ndis.c if_ndisvar.h 
  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.
  Revision  Changes    Path
  1.3       +8 -0      src/sys/compat/ndis/hal_var.h
  1.51      +79 -34    src/sys/compat/ndis/kern_ndis.c
  1.25      +5 -0      src/sys/compat/ndis/ndis_var.h
  1.13      +32 -7     src/sys/compat/ndis/ntoskrnl_var.h
  1.7       +45 -0     src/sys/compat/ndis/pe_var.h
  1.10      +118 -19   src/sys/compat/ndis/subr_hal.c
  1.55      +68 -21    src/sys/compat/ndis/subr_ndis.c
  1.34      +66 -75    src/sys/compat/ndis/subr_ntoskrnl.c
  1.53      +40 -46    src/sys/dev/if_ndis/if_ndis.c
  1.12      +7 -4      src/sys/dev/if_ndis/if_ndisvar.h

More information about the cvs-src mailing list