267654 |
20-Jun-2014 |
gjb |
Copy stable/9 to releng/9.3 as part of the 9.3-RELEASE cycle.
Approved by: re (implicit) Sponsored by: The FreeBSD Foundation
|
249288 |
08-Apr-2013 |
delphij |
MFC r247595:
Fix wrong assignment.
Submitted by: Sascha Wildner <saw online de> Obtained from: DragonFly rev 9568dd07a22a136e380e6c19a8ea188eb92976d5
|
233353 |
23-Mar-2012 |
kib |
MFC r231949: Fix found places where uio_resid is truncated to int.
Add the sysctl debug.iosize_max_clamp, enabled by default. Setting the sysctl to zero allows to perform the SSIZE_MAX-sized i/o requests from the usermode.
MFC r232493: Remove unneeded cast to u_int. The values as small enough to fit into int, beside the use of MIN macro which performs type promotions.
MFC r232494: Instead of incomplete handling of read(2)/write(2) return values that does not fit into registers, declare that we do not support this case using CTASSERT(), and remove endianess-unsafe code to split return value into td_retval.
While there, change the style of the sysctl debug.iosize_max_clamp definition.
MFC r232495: pipe_read(): change the type of size to int, and remove signed clamp. pipe_write(): change the type of desiredsize back to int, its value fits.
|
229739 |
06-Jan-2012 |
dim |
MFC r229004:
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.
|
225736 |
23-Sep-2011 |
kensmith |
Copy head to stable/9 as part of 9.0-RELEASE release cycle.
Approved by: re (implicit)
|
218985 |
23-Feb-2011 |
brucec |
Use the cprd_mem field when setting the start and length for a memory resource - the layout of cprd_port is identical but using cprd_mem makes the code easier to understand.
PR: kern/118493 Submitted by: Weongyo Jeong <weongyo.jeong at gmail.com> MFC after: 3 days
|
218909 |
21-Feb-2011 |
brucec |
Fix typos - remove duplicate "the".
PR: bin/154928 Submitted by: Eitan Adler <lists at eitanadler.com> MFC after: 3 days
|
217566 |
19-Jan-2011 |
mdf |
Fix a few more SYSCTL_PROC() that were missing a CTLFLAG type specifier.
|
216592 |
20-Dec-2010 |
tijl |
Merge amd64 and i386 bus.h and move the resulting header to x86. Replace the original amd64 and i386 headers with stubs.
Rename (AMD64|I386)_BUS_SPACE_* to X86_BUS_SPACE_* everywhere.
Reviewed by: imp (previous version), jhb Approved by: kib (mentor)
|
216242 |
06-Dec-2010 |
bschmidt |
Implement NdisGetRoutineAddress and MmGetSystemRoutineAddress used in newer Ralink drivers.
Submitted by: Paul B Mahol <onemda at gmail.com>
|
216050 |
29-Nov-2010 |
bschmidt |
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
|
216049 |
29-Nov-2010 |
bschmidt |
Some drivers rely on the existence of certain keys. The Atheros 9xxx driver for example requests the NetCfgInstanceId but doesn't check the returned status code and will happily access random memory instead.
Submitted by: Paul B Mahol <onemda at gmail.com> MFC after: 2 weeks
|
215782 |
23-Nov-2010 |
bschmidt |
Add prototype for InitializeSListHead().
|
215779 |
23-Nov-2010 |
bschmidt |
Add a few functions used in newer drivers. Fix RtlCompareMemory() while here.
Submitted by: Paul B Mahol <onemda@gmail.com>
|
215708 |
22-Nov-2010 |
bschmidt |
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 function.
Submitted by: Paul B Mahol <onemda at gmail.com>
|
215707 |
22-Nov-2010 |
bschmidt |
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>
|
215420 |
17-Nov-2010 |
bschmidt |
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>
|
215419 |
17-Nov-2010 |
bschmidt |
Use kmem_alloc_contig() to honour the cache_type variable.
Pointed out by: alc
|
215135 |
11-Nov-2010 |
bschmidt |
According to specs for MmAllocateContiguousMemorySpecifyCache() physically contiguous memory with requested restrictions must be allocated.
Submitted by: Paul B Mahol <onemda at gmail.com>
|
214798 |
04-Nov-2010 |
bschmidt |
Remove 4.x, 5.x and 6.x compatibility bits.
Submitted by: Paul B Mahol <onemda at gmail.com>
|
213461 |
05-Oct-2010 |
thompsa |
Use the printf-like capability from kproc_create().
Submitted by: Paul B Mahol
|
209102 |
12-Jun-2010 |
ed |
ANSIfy prototypes in subr_usbd.c.
Clang generates the following warnings when building subr_usbd.c:
| subr_usbd.c:598:13: warning: promoted type 'int' of K&R function | parameter is not compatible with the parameter type 'uint8_t' (aka | 'unsigned char') declared in a previous prototype | subr_usbd.c:627:13: warning: promoted type 'int' of K&R function | parameter is not compatible with the parameter type 'uint8_t' (aka | 'unsigned char') declared in a previous prototype | subr_usbd.c:649:13: warning: promoted type 'int' of K&R function | parameter is not compatible with the parameter type 'uint8_t' (aka | 'unsigned char') declared in a previous prototype
Instead of just ANSIfying these three prototypes, do it for the entire file.
Spotted by: clang
|
198819 |
02-Nov-2009 |
rpaulo |
Revert a functional change that snuck in.
|
198816 |
02-Nov-2009 |
rpaulo |
Fix a non-style change that snuck in.
Spotted by: danfe
|
198786 |
02-Nov-2009 |
rpaulo |
Big style cleanup. While there remove references to FreeBSD versions older than 6.0.
Submitted by: Paul B Mahol <onemda at gmail.com>
|
195031 |
26-Jun-2009 |
weongyo |
provides a extra write buffer when the NDIS driver want to send a request whose body has some datas through the default pipe.
Tested by: Nikos Vassiliadis <nvass9573 at gmx.com>
|
194682 |
23-Jun-2009 |
thompsa |
Fix a typeo in the frame len function to unbreak the build, make it shorter while I am here.
|
194677 |
23-Jun-2009 |
thompsa |
- Make struct usb_xfer opaque so that drivers can not access the internals - Reduce the number of headers needed for a usb driver, the common case is just usb.h and usbdi.h
|
194228 |
15-Jun-2009 |
thompsa |
s/usb2_/usb_|usbd_/ on all function names for the USB stack.
|
193644 |
07-Jun-2009 |
thompsa |
Rename usb pipes to endpoints as it better represents what they are, and struct usb_pipe may be used for a different purpose later on.
|
193045 |
29-May-2009 |
thompsa |
s/usb2_/usb_/ on all typedefs for the USB stack.
|
192984 |
28-May-2009 |
thompsa |
s/usb2_/usb_/ on all C structs for the USB stack.
|
192692 |
24-May-2009 |
antoine |
Remove an unused variable.
|
192090 |
14-May-2009 |
brueffer |
Remove an unused variable.
Found with: Coverity Prevent(tm) CID: 1167
|
192036 |
13-May-2009 |
brueffer |
Fix memory leak in an error case.
Found with: Coverity Prevent(tm) CID: 371 MFC after: 2 weeks
|
190734 |
05-Apr-2009 |
thompsa |
MFp4 //depot/projects/usb@159909
- make usb2_power_mask_t 16-bit - remove "usb2_config_sub" structure from "usb2_config". To compensate for this "usb2_config" has a new field called "usb_mode" which select for which mode the current xfer entry is active. Options are: a) Device mode only b) Host mode only (default-by-zero) c) Both modes. This change was scripted using the following sed script: "s/\.mh\././g". - the standard packet size table in "usb_transfer.c" is now a function, hence the code for the function uses less memory than the table itself.
Submitted by: Hans Petter Selasky
|
189950 |
18-Mar-2009 |
weongyo |
Some NDIS USB drivers try to call URB funcs like URB_FUNCTION_VENDOR_xxx or URB_FUNCTION_CLASS_xxx with HAL preemption lock that means it's non-sleepable during USB requests though usb2_do_request() requires a sleep so it needs to send queries to the default pipe without those interfaces to avoid sleep.
|
189942 |
18-Mar-2009 |
weongyo |
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.
|
189917 |
17-Mar-2009 |
weongyo |
grab NDIS USB lock instead of HAL preemption. This change should be happened in the previous.
|
189874 |
16-Mar-2009 |
weongyo |
use usb2_desc_foreach() to iterate the USB config descriptor instread of accessing structures directly to check some invalid descriptors.
Pointed by: hps
|
189719 |
12-Mar-2009 |
weongyo |
o change a lock model based on HAL preemption lock to a normal mtx. Based on the HAL preemption lock there is a problem on SMP machines and causes a panic. o When a device detached the current tactic to detach NDIS USB driver is to call SURPRISE_REMOVED event. So it don't need to call ndis_halt_nic() again. This fixes some page faults when some drivers work abnormal. o it assumes now that URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER is in DISPATCH_LEVEL (non-sleepable) and as further work URB_FUNCTION_VENDOR_XXX and URB_FUNCTION_CLASS_XXX should be.
Reviewed by: Hans Petter Selasky <hselasky_at_freebsd.org> Tested by: Paul B. Mahol <onemda_at_gmail.com>
|
189488 |
07-Mar-2009 |
weongyo |
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 drivers. o whitespace cleanup and style(9)
Obtained from: hps's original patch
|
189004 |
24-Feb-2009 |
rdivacky |
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
|
188939 |
23-Feb-2009 |
thompsa |
Move usb to a graveyard location under sys/legacy/dev, it is intended that the new USB2 stack will fully replace this for 8.0.
Remove kernel modules, a subsequent commit will update conf/files. Unhook usbdevs from the build.
|
187948 |
31-Jan-2009 |
obrien |
Change some movl's to mov's. Newer GAS no longer accept 'movl' instructions for moving between a segment register and a 32-bit memory location.
Looked at by: jhb
|
186540 |
28-Dec-2008 |
ganbold |
Remove unused variable.
Found with: Coverity Prevent(tm) CID: 542
Approved by: weongyo
|
186509 |
27-Dec-2008 |
weongyo |
fix a bug to handling the argument that it passed `device_t' but it's handled as `struct ndis_softc'. It'll cause a panic when the driver is detached.
|
186507 |
27-Dec-2008 |
weongyo |
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) - UNiCORN WL-54G (ZyDAS) - 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/...
|
183003 |
13-Sep-2008 |
thompsa |
Allow PAGE_SHIFT to already be defined.
Submitted by: Hans Petter Selasky
|
182371 |
28-Aug-2008 |
attilio |
Decontextualize the couplet VOP_GETATTR / VOP_SETATTR as the passed thread was always curthread and totally unuseful.
Tested by: Giovanni Trematerra <giovanni dot trematerra at gmail dot com>
|
180754 |
23-Jul-2008 |
weongyo |
when NDIS framework try to query/set informations NDIS drivers can return NDIS_STATUS_PENDING. In this case, it's waiting for 5 secs to get the response from drivers now. However, some NDIS drivers can send the response before NDIS framework gets ready to receive it so we might always be blocked for 5 secs in current implementation. NDIS framework should reset the event before calling NDIS driver's callback not after.
MFC after: 1 month
|
179806 |
15-Jun-2008 |
cokane |
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
|
179720 |
11-Jun-2008 |
weongyo |
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 NdisWriteErrorLogEntry().
|
179423 |
30-May-2008 |
weongyo |
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
|
179009 |
15-May-2008 |
weongyo |
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.
Reviewed by: thompsa
|
175872 |
01-Feb-2008 |
phk |
Give MEXTADD() another argument to make both void pointers to the free function controlable, instead of passing the KVA of the buffer storage as the first argument.
Fix all conventional users of the API to pass the KVA of the buffer as the first argument, to make this a no-op commit.
Likely break the only non-convetional user of the API, after informing the relevant committer.
Update the mbuf(9) manual page, which was already out of sync on this point.
Bump __FreeBSD_version to 800016 as there is no way to tell how many arguments a CPP macro needs any other way.
This paves the way for giving sendfile(9) a way to wait for the passed storage to have been accessed before returning.
This does not affect the memory layout or size of mbufs.
Parental oversight by: sam and rwatson.
No MFC is anticipated.
|
175294 |
13-Jan-2008 |
attilio |
VOP_LOCK1() (and so VOP_LOCK()) and VOP_UNLOCK() are only used in conjuction with 'thread' argument passing which is always curthread. Remove the unuseful extra-argument and pass explicitly curthread to lower layer functions, when necessary.
KPI results broken by this change, which should affect several ports, so version bumping and manpage update will be further committed.
Tested by: kris, pho, Diego Sardina <siarodx at gmail dot com>
|
174898 |
25-Dec-2007 |
rwatson |
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.
|
174240 |
03-Dec-2007 |
thompsa |
Implement functions required by some ndis drivers.
NdisIMCopySendPerPacketInfo [1] KeQuerySystemTime [1] KeTickCount [1] strncat [1] KeBugCheckEx
Submitted by: Marcin Simonides [1]
|
174150 |
02-Dec-2007 |
thompsa |
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.
|
174141 |
02-Dec-2007 |
thompsa |
Correct the nwbx_ies field type in struct ndis_wlan_bssid_ex.
PR: kern/118369 Submitted by: Weongyo Jeong
|
172836 |
20-Oct-2007 |
julian |
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.
|
171548 |
22-Jul-2007 |
thompsa |
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)
|
170487 |
10-Jun-2007 |
mjacob |
Quiesce warnings by initializing irql values to zero.
|
170307 |
05-Jun-2007 |
jeff |
Commit 14/14 of sched_lock decomposition. - Use thread_lock() rather than sched_lock for per-thread scheduling sychronization. - 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)
|
170152 |
31-May-2007 |
kib |
Revert UF_OPENING workaround for CURRENT. Change the VOP_OPEN(), vn_open() vnode operation and d_fdopen() cdev operation argument from being file descriptor index into the pointer to struct file.
Proposed and reviewed by: jhb Reviewed by: daichi (unionfs) Approved by: re (kensmith)
|
169802 |
20-May-2007 |
jeff |
- Move GDT/LDT locking into a seperate spinlock, removing the global scheduler lock from this responsibility.
Contributed by: Attilio Rao <attilio@FreeBSD.org> Tested by: jeff, kkenn
|
168421 |
06-Apr-2007 |
pjd |
We have strcasecmp() in libkern now.
|
166909 |
23-Feb-2007 |
jhb |
Use 'pause' in several places rather than trying to tsleep() on NULL (which triggers a KASSERT) or local variables. In the case of kern_ndis, the tsleep() actually used a common sleep address (curproc) making it susceptible to a premature wakeup.
|
166901 |
23-Feb-2007 |
piso |
o break newbus api: add a new argument of type driver_filter_t to bus_setup_intr()
o add an int return code to all fast handlers
o retire INTR_FAST/IH_FAST
For more info: http://docs.freebsd.org/cgi/getmsg.cgi?fetch=465712+0+current/freebsd-current
Reviewed by: many Approved by: re@
|
165544 |
25-Dec-2006 |
sam |
add entry points required by newer broadcom wireless driver
PR: kern/106131 Submitted by: Scot Hetzel MFC after: 2 weeks
|
161425 |
17-Aug-2006 |
imp |
while (0); -> while (0) in multi-line macros
|
159856 |
22-Jun-2006 |
dds |
Move conditional preprocessing out of the SYSCTL_ADD_STRING macro invocation. Per C99 6.10.3 paragraph 11 preprocessing directives appearing inside macro arguments yield undefined behavior.
|
159808 |
20-Jun-2006 |
jhb |
Conditionally acquire Giant around VFS operations.
|
159797 |
20-Jun-2006 |
jhb |
- Add a new linker_file_foreach() function that walks the list of linker file objects calling a user-specified predicate function on each object. The iteration terminates either when the entire list has been iterated over or the predicate function returns a non-zero value. linker_file_foreach() returns the value returned by the last invocation of the predicate function. It also accepts a void * context pointer that is passed to the predicate function as well. Using an iterator function avoids exposing linker internals to the rest of the kernel making locking simpler. - Use linker_file_foreach() instead of walking the list of linker files manually to lookup ndis files in ndis(4). - Use linker_file_foreach() to implement linker_hwpmc_list_objects().
|
159548 |
12-Jun-2006 |
jhb |
Forcefully turn off GPROF in this file if it is enabled as GPROF's attempt to use a macro for 'ret' doesn't play well with the wrappers trying to implement 'Pascal-style' calling conventions.
|
158651 |
16-May-2006 |
phk |
Since DELAY() was moved, most <machine/clock.h> #includes have been unnecessary.
|
152721 |
23-Nov-2005 |
wpaul |
Somehow memmove() got mapped to memset() in the patch table. Create a real memmove() implementation and use that instead.
|
152626 |
20-Nov-2005 |
wpaul |
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.
|
152423 |
14-Nov-2005 |
ru |
Unlike the rest of the world, NDIS code can access "struct ifnet" before is has been fully initialized by if_attach(). Account for that to avoid a null pointer dereference.
|
152399 |
13-Nov-2005 |
wpaul |
Restore backwards source compatibility with 6.x and 5.x.
|
152315 |
11-Nov-2005 |
ru |
- Store pointer to the link-level address right in "struct ifnet" rather than in ifindex_table[]; all (except one) accesses are through ifp anyway. IF_LLADDR() works faster, and all (except one) ifaddr_byindex() users were converted to use ifp->if_addr.
- Stop storing a (pointer to) Ethernet address in "struct arpcom", and drop the IFP2ENADDR() macro; all users have been converted to use IF_LLADDR() instead.
|
152257 |
10-Nov-2005 |
wpaul |
Implement RtlZeroMemory() and RtlCopyMemory(). This seems to allow the Broadcom Win64 wireless driver for the BCM4318 to work on amd64.
|
152159 |
07-Nov-2005 |
wpaul |
Change the definition for EXT_NDIS to EXT_NET_DRV. Since the latest mbuf code changes, MEXTADD() can be used to add an external buffer with arbitrary type, but mb_ext_free() won't let you free it.
|
152136 |
06-Nov-2005 |
wpaul |
The latest version of the Intel 2200BG/2915ABG driver (9.0.0.3-9) 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 routines.
- 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.
|
151977 |
02-Nov-2005 |
wpaul |
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 codes.
- Handle kthread_create() failure correctly in PsCreateSystemThread().
|
151967 |
02-Nov-2005 |
andre |
Retire MT_HEADER mbuf type and change its users to use MT_DATA.
Having an additional MT_HEADER mbuf type is superfluous and redundant as nothing depends on it. It only adds a layer of confusion. The distinction between header mbuf's and data mbuf's is solely done through the m->m_flags M_PKTHDR flag.
Non-native code is not changed in this commit. For compatibility MT_HEADER is mapped to MT_DATA.
Sponsored by: TCP/IP Optimization Fundraise 2005
|
151924 |
01-Nov-2005 |
wpaul |
Clean up one remaining 'multiple DPC thread' bogon: only bzero() one sizeof(kq_queue), not sizeof(kq_queue) * mp_ncpus.
|
151709 |
26-Oct-2005 |
wpaul |
Minor nit: in ntoskrnl_finddev(), only free the 'children' device_t array if device_find_children() actually returned a non-NULL array pointer.
|
151703 |
26-Oct-2005 |
wpaul |
Clean up and apply the fix for PR 83477. The calculation for locating the start of the section headers has to take into account the fact that the image_nt_header is really variable sized. It happens that the existing calculation is correct for _most_ production binaries produced by the Windows DDK, but if we get a binary with oddball offsets, the PE loader could crash.
Changes from the supplied patch are:
- We don't really need to use the IMAGE_SIZEOF_NT_HEADER() macro when computing how much of the header to return to callers of pe_get_optional_header(). While it's important to take the variable size of the header into account in other calculations, we never actually look at anything outside the non-variable portion of the header. This saves callers from having to allocate a variable sized buffer off the heap (I purposely tried to avoid using malloc() in subr_pe.c to make it easier to compile in both the -D_KERNEL and !-D_KERNEL case), and since we're copying into a buffer on the stack, we always have to copy the same amount of data or else we'll trash the stack something fierce.
- We need <stddef.h> to get offsetof() in the !-D_KERNEL case.
- ndiscvt.c needs the IMAGE_FIRST_SECTION() macro too, since it does a little bit of section pre-processing.
PR: kern/83477
|
151691 |
26-Oct-2005 |
wpaul |
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 fails.
|
151606 |
24-Oct-2005 |
wpaul |
Fix handling of message table messages that got broken when I converted NdisWriteErrorLogEntry() to use the RtlXXX unicode/ansi conversion routines.
|
151548 |
22-Oct-2005 |
wpaul |
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.
|
151529 |
21-Oct-2005 |
wpaul |
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.
|
151520 |
20-Oct-2005 |
wpaul |
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.
|
151451 |
18-Oct-2005 |
wpaul |
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.
|
151248 |
12-Oct-2005 |
wpaul |
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.
|
151207 |
10-Oct-2005 |
wpaul |
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 driver.)
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.
Whew.
|
149632 |
30-Aug-2005 |
andre |
Test the mbuf flags against the correct constant. The previous version worked as intended but only by chance. MT_HEADER == M_PKTHDR == 0x2.
|
147837 |
08-Jul-2005 |
rik |
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 off).
Submitted by: Eygene A. Ryabinkin <rea at rea dot mbslab dot kiae dot ru> Approved by: re (scottl) PR: 81767
|
147256 |
10-Jun-2005 |
brooks |
Stop embedding struct ifnet at the top of driver softcs. Instead the struct ifnet or the layer 2 common structure it was embedded in have been replaced with a struct ifnet pointer to be filled by a call to the new function, if_alloc(). The layer 2 common structure is also allocated via if_alloc() based on the interface type. It is hung off the new struct ifnet member, if_l2com.
This change removes the size of these structures from the kernel ABI and will allow us to better manage them as interfaces come and go.
Other changes of note: - Struct arpcom is no longer referenced in normal interface code. Instead the Ethernet address is accessed via the IFP2ENADDR() macro. To enforce this ac_enaddr has been renamed to _ac_enaddr. - The second argument to ether_ifattach is now always the mac address from driver private storage rather than sometimes being ac_enaddr.
Reviewed by: sobomax, sam
|
146734 |
29-May-2005 |
nyan |
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)
|
146428 |
20-May-2005 |
wpaul |
Missed kern_windrv.c in the last checkin.
|
146427 |
20-May-2005 |
wpaul |
Deal with a few bootstrap issues:
We can't call KeFlushQueuedDpcs() during bootstrap (cold == 1), since the flush operation sleeps to wait for completion, and we can't sleep here (clowns will eat us).
On an i386 SMP system, if we're loaded/probed/attached during bootstrap, smp_rendezvous() won't run us anywhere except CPU 0 (since the other CPUs aren't launched until later), which means we won't be able to set up the GDTs anywhere except CPU 0. To deal with this case, ctxsw_utow() now checks to see if the TID for the current processor has been properly initialized and sets up the GTD for the current CPU if not.
Lastly, in if_ndis.c:ndis_shutdown(), do an ndis_stop() to insure we really halt the NIC and stop interrupts from happening.
Note that loading a driver during bootstrap is, unfortunately, kind of a hit or miss sort of proposition. In Windows, the expectation is that by the time a given driver's MiniportInitialize() method is called, the system is already in 'multiuser' state, i.e. it's up and running enough to support all the stuff specified in the NDIS API, which includes the underlying OS-supplied facilities it implicitly depends on, such as having all CPUs running, having the DPC queues initialized, WorkItem threads running, etc. But in UNIX, a lot of that stuff won't work during bootstrap. This causes a problem since we need to call MiniportInitialize() at least once during ndis_attach() in order to find out what kind of NIC we have and learn its station address.
What this means is that some cards just plain won't work right if you try to pre-load the driver along with the kernel: they'll only be probed/attach correctly if the driver is kldloaded _after_ the system has reached multiuser. I can't really think of a way around this that would still preserve the ability to use an NDIS device for diskless booting.
|
146424 |
20-May-2005 |
wpaul |
In ndis_halt_nic(), invalidate the miniportadapterctx early to try and prevent anything from making calls to the NIC while it's being shut down. This is yet another attempt to stop things like mdnsd from trying to poke at the card while it's not properly initialized and panicking the system.
Also, remove unneeded debug message from if_ndis.c.
|
146364 |
19-May-2005 |
wpaul |
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 avoided.
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.
|
146274 |
16-May-2005 |
wpaul |
Remove harmless bit of leftover debug code.
|
146273 |
16-May-2005 |
wpaul |
Correct some problems with workitem usage. NdisScheduleWorkItem() does not use exactly the same workitem sturcture as ExQueueWorkItem() like I originally thought it did.
|
146230 |
15-May-2005 |
wpaul |
Add support for NdisMEthIndicateReceive() and MiniportTransferData(). The Ralink RT2500 driver uses this API instead of NdisMIndicateReceivePacket().
Drivers use NdisMEthIndicateReceive() when they know they support 802.3 media and expect to hand their packets only protocols that want to deal with that particular media type. With this API, the driver does not manage its own NDIS_PACKET/NDIS_BUFFER structures. Instead, it lets bound protocols have a peek at the data, and then they supply an NDIS_PACKET/NDIS_BUFFER combo to the miniport driver, into which it copies the packet data.
Drivers use NdisMIndicateReceivePacket() to allow their packets to be read by any protocol, not just those bound to 802.3 media devices.
To make this work, we need an internal pool of NDIS_PACKETS for receives. Currently, we check to see if the driver exports a MiniportTransferData() method in its characteristics structure, and only allocate the pool for drivers that have this method.
This should allow the RT2500 driver to work correctly, though I still have to fix ndiscvt(8) to parse its .inf file properly.
Also, change kern_ndis.c:ndis_halt_nic() to reap timers before acquiring NDIS_LOCK(), since the reaping process might entail sleeping briefly (and we can't sleep with a lock held).
|
146016 |
08-May-2005 |
wpaul |
More fixes for multibus drivers. When calling out to the match function in if_ndis_pci.c and if_ndis_pccard.c, provide the bustype too so the stubs can ignore devlists that don't concern them.
|
146015 |
08-May-2005 |
wpaul |
Fix support for Windows drivers that support both PCI and PCMCIA devices at the same time.
Fix if_ndis_pccard.c so that it sets sc->ndis_dobj and sc->ndis_regvals.
Correct IMPORT_SFUNC() macros for the READ_PORT_BUFFER_xxx() routines, which take 3 arguments, not 2.
This fixes it so that the Windows driver for my Cisco Aironet 340 PCMCIA card works again. (Yes, I know the an(4) driver supports this card natively, but it's the only PCMCIA device I have with a Windows XP driver.)
|
145999 |
08-May-2005 |
wpaul |
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.
|
145935 |
05-May-2005 |
wpaul |
Cast 64 bit quantity to uintmax_t to print it with %jx. This is technically a no-op since uintmax_t is uint64_t on all currently supported architectures, but we should use an explicit cast instead of depending on this obscure coincidence.
|
145906 |
05-May-2005 |
wpaul |
Use %jx instead of %qx to silence compiler warning on amd64.
|
145898 |
05-May-2005 |
wpaul |
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 correctly).
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.
|
145896 |
05-May-2005 |
wpaul |
Remove extranaous free() of ASCII filename from NdisOpenFile().
Oh, one additional change I forgot to mention in the last commit: NdisOpenFile() was broken in the case for firmware files that were pre-loaded as modules. When searching for the module in NdisOpenFile(), we would match against a symbol name, which would contain the string we were looking for, then save a pointer to the linker file handle. Later, in NdisMapFile(), we would refer to the filename hung off this handle when trying to find the starting address symbol. Only problem is, this filename is different from the embedded symbol name we're searching for, so the mapping would fail. I found this problem while testing the AirGo driver, which requires a small firmware file.
|
145895 |
05-May-2005 |
wpaul |
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() API.)
- Change if_ndis.c to use the NdisScheduleWorkItem() interface for scheduling tasks.
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.
|
145485 |
24-Apr-2005 |
wpaul |
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.
|
145205 |
17-Apr-2005 |
wpaul |
Now that the GDT has been reorganized and GNDIS_SEL has been reserved for us, use it if it's available, otherwise default to using slot 7 as before.
|
145133 |
16-Apr-2005 |
wpaul |
When setting up the new stack for a function in x86_64_wrap(), make sure to make it 16-byte aligned, in keeping with amd64 calling convention requirements.
Submitted by: Mikore Li at sun dot com
|
144913 |
11-Apr-2005 |
wpaul |
In winx32_wrap.S, preserve return values in the fastcall and regparm wrappers by pushing them onto the stack rather than keeping them in %esi and %edi.
|
144888 |
11-Apr-2005 |
wpaul |
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.
|
144495 |
01-Apr-2005 |
wpaul |
Fix another KeInitializeDpc()/amd64 calling convention issue: ndis_intrhand() has to be wrapped for the same reason as ndis_timercall().
|
144428 |
31-Mar-2005 |
wpaul |
Apparently I'm cursed. ndis_findwrap() should be searching ndis_functbl, not ntoskrnl_functbl.
|
144402 |
31-Mar-2005 |
wpaul |
Fix an amd64 issue I overlooked. When setting up a callout to ndis_timercall() in NdisMInitializeTimer(), we can't use the raw function pointer. This is because ntoskrnl_run_dpc() expects to invoke a function with Microsoft calling conventions. On i386, this works because ndis_timercall() is declared with the __stdcall attribute, but this is a no-op on amd64. To do it correctly, we have to generate a wrapper for ndis_timercall() and us the wrapper instead of of the raw function pointer.
Fix this by adding ndis_timercall() to the funcptr table in subr_ndis.c, and create ndis_findwrap() to extract the wrapped function from the table in NdisMInitializeTimer() instead of just passing ndis_timercall() to KeInitializeDpc() directly.
|
144342 |
30-Mar-2005 |
wpaul |
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.
|
144317 |
30-Mar-2005 |
wpaul |
Remove a couple of #ifdef 0'ed code blocks left over from Atheros debugging.
Remember to reset ndis_pendingreq to NULL when bailing out of ndis_set_info() or ndis_get_info() due to miniportadapterctx not being set.
|
144256 |
28-Mar-2005 |
wpaul |
The filehandle allocated in NdisOpenFile() is allocated using ExAllocatePoolWithTag(), not malloc(), so it should be released with ExFreePool(), not free(). Fix a couple if instances of free(fh, ...) that got overlooked.
|
144254 |
28-Mar-2005 |
wpaul |
Another Coverity fix from Sam: add NULL pointer test in NdisMFreeSharedMemory() (if the list is already empty, just bail).
|
144253 |
28-Mar-2005 |
wpaul |
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().
|
144251 |
28-Mar-2005 |
wpaul |
Fix resource leak found by Coverity (via Sam Leffler).
|
144250 |
28-Mar-2005 |
wpaul |
Fix for amd64.
|
144248 |
28-Mar-2005 |
wpaul |
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.
|
144240 |
28-Mar-2005 |
wpaul |
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.
|
144239 |
28-Mar-2005 |
wpaul |
Spell '0' as 'FALSE' when initializing npp_validcounts. (Doesn't change the code, but emphasises that this field is used as a boolean.)
|
144238 |
28-Mar-2005 |
wpaul |
Unbreak the build: correct the resource list traversal code for __FreeBSD_version >= 600022.
|
144176 |
27-Mar-2005 |
wpaul |
Argh. PCI resource list became an STAILQ instead of an SLIST. Try to deal with this while maintaining backards source compatibility with stable.
|
144175 |
27-Mar-2005 |
wpaul |
Check in ntoskrnl_var.h, which should have been included in the previous commit.
|
144174 |
27-Mar-2005 |
wpaul |
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 subr_ndis.c.
- 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.
|
143801 |
18-Mar-2005 |
phk |
s/SLIST/STAILQ/ /imp/a\ pointy hat .
|
143204 |
07-Mar-2005 |
wpaul |
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 wrong.)
- 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.
|
143086 |
03-Mar-2005 |
wpaul |
MAXPATHLEN is 1024, which means NdisOpenFile() and ndis_find_sym() were both consuming 1K of stack space. This is unfriendly. Allocate the buffers off the heap instead. It's a little slower, but these aren't performance critical routines.
Also, add a spinlock to NdisAllocatePacketPool(), NdisAllocatePacket(), NdisFreePacketPool() and NdisFreePacket(). The pool is maintained as a linked list. I don't know for a fact that it can be corrupted, but why take chances.
|
142931 |
01-Mar-2005 |
wpaul |
In windrv_load(), I was allocating the driver object using malloc(sizeof(device_object), ...) by mistake. Correct this, and rename "dobj" to "drv" to make it a bit clearer what this variable is supposed to be.
Spotted by: Mikore Li at Sun dot comnospamplzkthx
|
142553 |
26-Feb-2005 |
wpaul |
Don't need to do MmInitializeMdl() in ndis_mtop() anymore: IoInitializeMdl() does it internally (and doing it again here messes things up).
|
142530 |
26-Feb-2005 |
wpaul |
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() directly.
Inspired by: discussion with Giridhar Pemmasani
|
142497 |
25-Feb-2005 |
wpaul |
Add macros to construct Windows IOCTL codes, and to extract function codes from an IOCTL. (The USB module will need them later.)
|
142443 |
25-Feb-2005 |
wpaul |
Fix a couple of callback instances that should have been wrapped with MSCALLx().
Add definition for STATUS_PENDING error code.
|
142433 |
25-Feb-2005 |
wpaul |
Compute the right length to use with bzero() when initializing an IRP in IoInitializeIrp() (must use IoSizeOfIrp() to account for the stack locations).
|
142399 |
24-Feb-2005 |
wpaul |
- Correct one aspect of the driver_object/device_object/IRP framework: when we create a PDO, the driver_object associated with it is that of the parent driver, not the driver we're trying to attach. For example, if we attach a PCI device, the PDO we pass to the NdisAddDevice() function should contain a pointer to fake_pci_driver, not to the NDIS driver itself. For PCI or PCMCIA devices this doesn't matter because the child never needs to talk to the parent bus driver, but for USB, the child needs to be able to send IRPs to the parent USB bus driver, and for that to work the parent USB bus driver has to be hung off the PDO.
This involves modifying windrv_lookup() so that we can search for bus drivers by name, if necessary. Our fake bus drivers attach themselves as "PCI Bus," "PCCARD Bus" and "USB Bus," so we can search for them using those names.
The individual attachment stubs now create and attach PDOs to the parent bus drivers instead of hanging them off the NDIS driver's object, and in if_ndis.c, we now search for the correct driver object depending on the bus type, and use that to find the correct PDO.
With this fix, I can get my sample USB ethernet driver to deliver an IRP to my fake parent USB bus driver's dispatch routines.
- Add stub modules for USB support: subr_usbd.c, usbd_var.h and if_ndis_usb.c. The subr_usbd.c module is hooked up the build but currently doesn't do very much. It provides the stub USB parent driver object and a dispatch routine for IRM_MJ_INTERNAL_DEVICE_CONTROL. The only exported function at the moment is USBD_GetUSBDIVersion(). The if_ndis_usb.c stub compiles, but is not hooked up to the build yet. I'm putting these here so I can keep them under source code control as I flesh them out.
|
142387 |
24-Feb-2005 |
wpaul |
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.
|
142311 |
23-Feb-2005 |
wpaul |
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.
|
142037 |
18-Feb-2005 |
wpaul |
Fix a couple of u_int_foos that should have been uint_foos.
|
142035 |
18-Feb-2005 |
wpaul |
Make the Win64 -> ELF64 template a little smaller by using a string copy op to shift arguments on the stack instead of transfering each argument one by one through a register. Probably doesn't affect overall operation, but makes the code a little less grotty and easier to update later if I choose to make the wrapper handle more args. Also add comments.
|
141990 |
16-Feb-2005 |
wpaul |
Remove redundant label.
|
141982 |
16-Feb-2005 |
wpaul |
Fix freeing of custom driver extensions. (ExFreePool() was being called with the wrong pointer.)
|
141980 |
16-Feb-2005 |
wpaul |
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.
|
141963 |
16-Feb-2005 |
wpaul |
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.
|
141524 |
08-Feb-2005 |
wpaul |
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(), IoInitializeIrp() - 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 kern_ndis.c). - 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.
|
140827 |
25-Jan-2005 |
wpaul |
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.
|
140751 |
24-Jan-2005 |
wpaul |
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 applicable.
- 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.
|
140267 |
14-Jan-2005 |
wpaul |
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.
|
139743 |
05-Jan-2005 |
imp |
Start each of the license/copyright comments with /*-
|
139451 |
30-Dec-2004 |
jhb |
Stop explicitly touching td_base_pri outside of the scheduler and simply set a thread's priority via sched_prio() when that is the desired action. The schedulers will start managing td_base_pri internally shortly.
|
135399 |
17-Sep-2004 |
bms |
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
|
133880 |
16-Aug-2004 |
wpaul |
I'm a dumbass: remember to initialize fh->nf_map to NULL in ndis_open_file() in the module loading case.
|
133877 |
16-Aug-2004 |
wpaul |
The Texas Instruments ACX111 driver wants srand(), so provide it.
|
133876 |
16-Aug-2004 |
wpaul |
Make the Texas Instruments 802.11g chipset work with the NDISulator. This was tested with a Netgear WG311v2 802.11b/g PCI card. Things that were fixed:
- This chip has two memory mapped regions, one at PCIR_BAR(0) and the other at PCIR_BAR(1). This is a little different from the other chips I've seen with two PCI shared memory regions, since they tend to have the second BAR ad PCIR_BAR(2). if_ndis_pci.c tests explicitly for PCIR_BAR(2). This has been changed to simply fill in ndis_res_mem first and ndis_res_altmem second, if a second shared memory range exists. Given that NDIS drivers seem to scan for BARs in ascending order, I think this should be ok.
- Fixed the code that tries to process firmware images that have been loaded as .ko files. To save a step, I was setting up the address mapping in ndis_open_file(), but ndis_map_file() flags pre-existing mappings as an error (to avoid duplicate mappings). Changed this so that the mapping is now donw in ndis_map_file() as expected.
- Made the typedef for 'driver_entry' explicitly include __stdcall to silence gcc warning in ndis_load_driver().
NOTE: the Texas Instruments ACX111 driver needs firmware. With my card, there were 3 .bin files shipped with the driver. You must either put these files in /compat/ndis or convert them with ndiscvt -f and kldload them so the driver can use them. Without the firmware image, the NIC won't work.
|
133127 |
04-Aug-2004 |
wpaul |
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().
|
132980 |
01-Aug-2004 |
wpaul |
In ndis_alloc_bufpool() and ndis_alloc_packetpool(), the test to see if allocating pool memory succeeded was checking the wrong pointer (should have been looking at *pool, not pool). Corrected this.
|
132973 |
01-Aug-2004 |
wpaul |
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.
|
132468 |
20-Jul-2004 |
wpaul |
*sigh* Fix source code compatibility with 5.2.1-RELEASE _again_. (Make kdb stuff conditional.)
|
131953 |
11-Jul-2004 |
wpaul |
Make NdisReadPcmciaAttributeMemory() and NdisWritePcmciaAttributeMemory() actually work.
Make the PCI and PCCARD attachments provide a bus_get_resource_list() method so that resource listing for PCCARD works. PCCARD does not have a bus_get_resource_list() method (yet), so I faked up the resource list management in if_ndis_pccard.c, and added bus_get_resource_list() methods to both if_ndis_pccard.c and if_ndis_pci.c. The one in the PCI attechment just hands off to the PCI bus code. The difference is transparent to the NDIS resource handler code.
Fixed ndis_open_file() so that opening files which live on NFS filesystems work: pass an actual ucred structure to VOP_GETATTR() (NFS explodes if the ucred structure is NOCRED).
Make NdisMMapIoSpace() handle mapping of PCMCIA attribute memory resources correctly.
Turn subr_ndis.c:my_strcasecmp() into ndis_strcasecmp() and export it so that if_ndis_pccard.c can use it, and junk the other copy of my_strcasecmp() from if_ndis_pccard.c.
|
131909 |
10-Jul-2004 |
marcel |
Update for the KDB framework: o Call kdb_enter() instead of Debugger().
While here, remove a redundant return.
|
131750 |
07-Jul-2004 |
wpaul |
Fix two problems:
- In subr_ndis.c:ndis_allocate_sharemem(), create the busdma tags used for shared memory allocations with a lowaddr of 0x3E7FFFFF. This forces the buffers to be mapped to physical/bus addresses within the first 1GB of physical memory. It seems that at least one card (Linksys Instant Wireless PCI V2.7) depends on this behavior. I don't know if this is a hardware restriction, or if the NDIS driver for this card is truncating the addresses itself, but using physical/bus addresses beyong the 1GB limit causes initialization failures.
- Create am NDIS_INITIALIZED() macro in if_ndisvar.h and use it in if_ndis.c to test whether the device has been initialized rather than checking for the presence of the IFF_UP flag in if_flags. While debugging the previous problem, I noticed that bringing up the device would always produce failures from ndis_setmulti(). It turns out that the following steps now occur during device initialization:
- IFF_UP flag is set in if_flags - ifp->if_ioctl() called with SIOCSIFADDR (which we don't handle) - ifp->if_ioctl() called with SIOCADDMULTI - ifp->if_ioctl() called with SIOCADDMULTI (again) - ifp->if_ioctl() called with SIOCADDMULTI (yet again) - ifp->if_ioctl() called with SIOCSIFFLAGS
Setting the receive filter and multicast filters can only be done when the underlying NDIS driver has been initialized, which is done by ifp->if_init(). However, we don't call ifp->if_init() until ifp->if_ioctl() is called with SIOCSIFFLAGS and IFF_UP has been set. It appears that now, the network stack tries to add multicast addresses to interface's filter before those steps occur. Normally, ndis_setmulti() would trap this condition by checking for the IFF_UP flag, but the network code has in fact set this flag already, so ndis_setmulti() is fooled into thinking the interface has been initialized when it really hasn't.
It turns out this is usually harmless because the ifp->if_init() routine (in this case ndis_init()) will set up the multicast filter when it initializes the hardware anyway, and the underlying routines (ndis_get_info()/ndis_set_info()) know that the driver/NIC haven't been initialized yet, but you end up spurious error messages on the console all the time.
Something tells me this new behavior isn't really correct. I think the intention was to fix it so that ifp->if_init() is only called once when we ifconfig an interface up, but the end result seems a little bogus: the change of the IFF_UP flag should be propagated down to the driver before calling any other ioctl() that might actually require the hardware to be up and running.
|
130166 |
07-Jun-2004 |
wpaul |
Add another 5.2.1 source compatibility tweak: acquire Giant before calling kthread_exit() if FreeBSD_version is old enough.
|
130097 |
04-Jun-2004 |
des |
Take advantage of the dev sysctl tree.
Approved by: wpaul
|
130052 |
04-Jun-2004 |
wpaul |
Grrr. Really check subr_ndis.c in this time. (fixed my_strcasecmp())
|
129970 |
01-Jun-2004 |
wpaul |
Explicitly #include <sys/module.h> instead of depending on <sys/kernel.h> to do it for us.
|
129850 |
29-May-2004 |
wpaul |
Fix build with ndisulator: Add prototype for my_strcasecmp().
|
129834 |
29-May-2004 |
wpaul |
In subr_ndis.c, when searching for keys in our make-pretend registry, make the key name matching case-insensitive. There are some drivers and .inf files that have mismatched cases, e.g. the driver will look for "AdhocBand" whereas the .inf file specifies a registry key to be created called "AdHocBand." The mismatch is probably a typo that went undetected (so much for QA), but since Windows seems to be case-insensitive, we should be too.
In if_ndis.c, initialize rates and channels correctly so that specify frequences correctly when trying to set channels in the 5Ghz band, and so that 802.11b rates show up for some a/b/g cards (which otherwise appear to have no 802.11b modes).
Also, when setting OID_802_11_CONFIGURATION in ndis_80211_setstate(), provide default values for the beacon interval, ATIM window and dwelltime. The Atheros "Aries" driver will crash if you try to select ad-hoc mode and leave the beacon interval set to 0: it blindly uses this value and does a division by 0 in the interrupt handler, causing an integer divide trap.
|
128780 |
30-Apr-2004 |
wpaul |
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 workaround.
|
128546 |
22-Apr-2004 |
wpaul |
Ok, _really_ fix the Intel 2100B Centrino deadlock problems this time. (I hope.)
My original instinct to make ndis_return_packet() asynchronous was correct. Making ndis_rxeof() submit packets to the stack asynchronously fixes one recursive spinlock acquisition, but it's also possible for it to happen via the ndis_txeof() path too. So:
- In if_ndis.c, revert ndis_rxeof() to its old behavior (and don't bother putting ndis_rxeof_serial() back since we don't need it anymore).
- In kern_ndis.c, make ndis_return_packet() submit the call to the MiniportReturnPacket() function to the "ndis swi" thread so that it always happens in another context no matter who calls it.
|
128449 |
20-Apr-2004 |
wpaul |
Correct the AT_DISPATCH_LEVEL() macro to match earlier changes.
|
128447 |
19-Apr-2004 |
wpaul |
Try to handle recursive attempts to raise IRQL to DISPATCH_LEVEL better (among other things).
|
128406 |
18-Apr-2004 |
wpaul |
In ntoskrnl_unlock_dpc(), use atomic_store instead of atomic_cmpset to give up the spinlock.
Suggested by: bde
|
128295 |
16-Apr-2004 |
wpaul |
- Use memory barrier with atomic operations in ntoskrnl_lock_dpc() and ntoskrnl_unlocl_dpc(). - hal_raise_irql(), hal_lower_irql() and hal_irql() didn't work right on SMP (priority inheritance makes things... interesting). For now, use only two states: DISPATCH_LEVEL (PI_REALTIME) and PASSIVE_LEVEL (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.
|
128229 |
14-Apr-2004 |
wpaul |
Continue my efforts to imitate Windows as closely as possible by attempting to duplicate Windows spinlocks. Windows spinlocks differ from FreeBSD spinlocks in the way they block preemption. FreeBSD spinlocks use critical_enter(), which masks off _all_ interrupts. This prevents any other threads from being scheduled, but it also prevents ISRs from running. In Windows, preemption is achieved by raising the processor IRQL to DISPATCH_LEVEL, which prevents other threads from preempting you, but does _not_ prevent device ISRs from running. (This is essentially what Solaris calls dispatcher locks.) The Windows spinlock itself (kspin_lock) is just an integer value which is atomically set when you acquire the lock and atomically cleared when you release it.
FreeBSD doesn't have IRQ levels, so we have to cheat a little by using thread priorities: normal thread priority is PASSIVE_LEVEL, lowest interrupt thread priority is DISPATCH_LEVEL, highest thread priority is DEVICE_LEVEL (PI_REALTIME) and critical_enter() is HIGH_LEVEL. In practice, only PASSIVE_LEVEL and DISPATCH_LEVEL matter to us. The immediate benefit of all this is that I no longer have to rely on a mutex pool.
Now, I'm sure many people will be seized by the urge to criticize me for doing an end run around our own spinlock implementation, but it makes more sense to do it this way. Well, it does to me anyway.
Overview of the changes:
- Properly implement hal_lock(), hal_unlock(), hal_irql(), hal_raise_irql() and hal_lower_irql() so that they more closely resemble their Windows counterparts. The IRQL is determined by thread priority.
- Make ntoskrnl_lock_dpc() and ntoskrnl_unlock_dpc() do what they do in Windows, which is to atomically set/clear the lock value. These routines are designed to be called from DISPATCH_LEVEL, and are actually half of the work involved in acquiring/releasing spinlocks.
- Add FASTCALL1(), FASTCALL2() and FASTCALL3() macros/wrappers that allow us to call a _fastcall function in spite of the fact that our version of gcc doesn't support __attribute__((__fastcall__)) yet. The macros take 1, 2 or 3 arguments, respectively. We need to call hal_lock(), hal_unlock() etc... ourselves, but can't really invoke the function directly. I could have just made the underlying functions native routines and put _fastcall wrappers around them for the benefit of Windows binaries, but that would create needless bloat.
- Remove ndis_mtxpool and all references to it. We don't need it anymore.
- Re-implement the NdisSpinLock routines so that they use hal_lock() and friends like they do in Windows.
- Use the new spinlock methods for handling lookaside lists and linked list updates in place of the mutex locks that were there before.
- Remove mutex locking from ndis_isr() and ndis_intrhand() since they're already called with ndis_intrmtx held in if_ndis.c.
- Put ndis_destroy_lock() code under explicit #ifdef notdef/#endif. It turns out there are some drivers which stupidly free the memory in which their spinlocks reside before calling ndis_destroy_lock() on them (touch-after-free bug). The ADMtek wireless driver is guilty of this faux pas. (Why this doesn't clobber Windows I have no idea.)
- Make NdisDprAcquireSpinLock() and NdisDprReleaseSpinLock() into real functions instead of aliasing them to NdisAcaquireSpinLock() and NdisReleaseSpinLock(). The Dpr routines use KeAcquireSpinLockAtDpcLevel() level and KeReleaseSpinLockFromDpcLevel(), which acquires the lock without twiddling the IRQL.
- In ndis_linksts_done(), do _not_ call ndis_80211_getstate(). Some drivers may call the status/status done callbacks as the result of setting an OID: ndis_80211_getstate() gets OIDs, which means we might cause the driver to recursively access some of its internal structures unexpectedly. The ndis_ticktask() routine will call ndis_80211_getstate() for us eventually anyway.
- Fix the channel setting code a little in ndis_80211_setstate(), and initialize the channel to IEEE80211_CHAN_ANYC. (The Microsoft spec says you're not supposed to twiddle the channel in BSS mode; I may need to enforce this later.) This fixes the problems I was having with the ADMtek adm8211 driver: we were setting the channel to a non-standard default, which would cause it to fail to associate in BSS mode.
- Use hal_raise_irql() to raise our IRQL to DISPATCH_LEVEL when calling certain miniport routines, per the Microsoft documentation.
I think that's everything. Hopefully, other than fixing the ADMtek driver, there should be no apparent change in behavior.
|
128012 |
07-Apr-2004 |
wpaul |
In ndis_convert_res(), initialize the head of our temporary list before calling BUS_GET_RESOURCE_LIST(). Previously, the list head would only be initialized if BUS_GET_RESOURCE_LIST() succeeded; it needs to be initialized unconditionally so that the list cleanup code won't trip over potential stack garbage.
|
127887 |
05-Apr-2004 |
wpaul |
- The MiniportReset() function can return NDIS_STATUS_PENDING, in which case we should wait for the resetdone handler to be called before returning.
- When providing resources via ndis_query_resources(), uses the computed rsclen when using bcopy() to copy out the resource data rather than the caller-supplied buffer length.
- Avoid using ndis_reset_nic() in if_ndis.c unless we really need to reset the NIC because of a problem.
- Allow interrupts to be fielded during ndis_attach(), at least as far as allowing ndis_isr() and ndis_intrhand() to run.
- Use ndis_80211_rates_ex when probing for supported rates. Technically, this isn't supposed to work since, although Microsoft added the extended rate structure with the NDIS 5.1 update, the spec still says that the OID_802_11_SUPPORTED_RATES OID uses ndis_80211_rates. In spite of this, it appears some drivers use it anyway.
- When adding in our guessed rates, check to see if they already exist so that we avoid any duplicates.
- Add a printf() to ndis_open_file() that alerts the user when a driver attempts to open a file under /compat/ndis.
With these changes, I can get the driver for the SMC 2802W 54g PCI card to load and run. This board uses a Prism54G chip. Note that in order for this driver to work, you must place the supplied smc2802w.arm firmware image under /compat/ndis. (The firmware is not resident on the device.)
Note that this should also allow the 3Com 3CRWE154G72 card to work as well; as far as I can tell, these cards also use a Prism54G chip.
|
127552 |
29-Mar-2004 |
wpaul |
Add missing cprd_flags member to partial resource structure in resource_var.h.
In kern_ndis.c:ndis_convert_res(), fill in the cprd_flags and cprd_sharedisp fields as best we can.
In if_ndis.c:ndis_setmulti(), don't bother updating the multicast filter if our multicast address list is empty.
Add some missing updates to ndis_var.h and ntoskrnl_var.h that I forgot to check in when I added the KeDpc stuff.
|
127503 |
27-Mar-2004 |
wpaul |
Apparently, some atheros drivers want rand(), so implement it (in terms of random()).
Requested by: juli Bribe offered: tacos
|
127411 |
25-Mar-2004 |
wpaul |
- In subr_ndis.c:ndis_init_event(), initialize events as notification objects rather than synchronization objects. When a sync object is signaled, only the first thread waiting on it is woken up, and then it's automatically reset to the not-signaled state. When a notification object is signaled, all threads waiting on it will be woken up, and it remains in the signaled state until someone resets it manually. We want the latter behavior for NDIS events.
- In kern_ndis.c:ndis_convert_res(), we have to create a temporary copy of the list returned by BUS_GET_RESOURCE_LIST(). When the PCI bus code probes resources for a given device, it enters them into a singly linked list, head first. The result is that traversing this list gives you the resources in reverse order. This means when we create the Windows resource list, it will be in reverse order too. Unfortunately, this can hose drivers for devices with multiple I/O ranges of the same type, like, say, two memory mapped I/O regions (one for registers, one to map the NVRAM/bootrom/whatever). Some drivers test the range size to figure out which region is which, but others just assume that the resources will be listed in ascending order from lowest numbered BAR to highest. Reversing the order means such drivers will choose the wrong resource as their I/O register range.
Since we can't traverse the resource SLIST backwards, we have to make a temporary copy of the list in the right order and then build the Windows resource list from that. I suppose we could just fix the PCI bus code to use a TAILQ instead, but then I'd have to track down all the consumers of the BUS_GET_RESOURCE_LIST() and fix them too.
|
127393 |
25-Mar-2004 |
wpaul |
- 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.)
|
127320 |
22-Mar-2004 |
wpaul |
Remove another case of grabbing Giant before doing a kthread_exit() which is now no longer needed.
|
127311 |
22-Mar-2004 |
wpaul |
I'm a dumbass: the test in the MOD_SHUTDOWN case in ndis_modevent() that checks to see if any devices are still in the devlist was reversed.
|
127284 |
22-Mar-2004 |
wpaul |
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 safe.
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.
|
127248 |
20-Mar-2004 |
wpaul |
- 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.
|
127026 |
15-Mar-2004 |
wpaul |
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.
|
126834 |
11-Mar-2004 |
wpaul |
Fix mind-o: sanity check in ndis_disable_ndis() is not sane.
|
126833 |
11-Mar-2004 |
wpaul |
Fix the problem with the Cisco Aironet 340 PCMCIA card. Most newer drivers for Windows are deserialized miniports. Such drivers maintain their own queues and do their own locking. This particular driver is not deserialized though, and we need special support to handle it correctly.
Typically, in the ndis_rxeof() handler, we pass all incoming packets directly to (*ifp->if_input)(). This in turn may cause another thread to run and preempt us, and the packet may actually be processed and then released before we even exit the ndis_rxeof() routine. The problem with this is that releasing a packet calls the ndis_return_packet() function, which hands the packet and its buffers back to the driver. Calling ndis_return_packet() before ndis_rxeof() returns will screw up the driver's internal queues since, not being deserialized, it does no locking.
To avoid this problem, if we detect a serialized driver (by checking the attribute flags passed to NdisSetAttributesEx(), we use an alternate ndis_rxeof() handler, ndis_rxeof_serial(), which puts the call to (*ifp->if_input)() on the NDIS SWI work queue. This guarantees the packet won't be processed until after ndis_rxeof_serial() returns.
Note that another approach is to always copy the packet data into another mbuf and just let the driver retain ownership of the ndis_packet structure (ndis_return_packet() never needs to be called in this case). I'm not sure which method is faster.
|
126795 |
10-Mar-2004 |
wpaul |
Fix several issues related to the KeInitializeTimer() etc... API stuff that I added recently:
- When a periodic timer fires, it's automatically re-armed. We must make sure to re-arm the timer _before_ invoking any caller-supplied defered procedure call: the DPC may choose to call KeCancelTimer(), and re-arming the timer after the DPC un-does the effect of the cancel.
- Fix similar issue with periodic timers in subr_ndis.c.
- When calling KeSetTimer() or KeSetTimerEx(), if the timer is already pending, untimeout() it first before timeout()ing it again.
- The old Atheros driver for the 5211 seems to use KeSetTimerEx() incorrectly, or at the very least in a very strange way that doesn't quite follow the Microsoft documentation. In one case, it calls KeSetTimerEx() with a duetime of 0 and a period of 5000. The Microsoft documentation says that negative duetime values are relative to the current time and positive values are absolute. But it doesn't say what's supposed to happen with positive values that less than the current time, i.e. absolute values that are in the past.
Lacking any further information, I have decided that timers with positive duetimes that are in the past should fire right away (or in our case, after only 1 tick). This also takes care of the other strange usage in the Atheros driver, where the duetime is specified as 500000 and the period is 50. I think someone may have meant to use -500000 and misinterpreted the documentation.
- Also modified KeWaitForSingleObject() and KeWaitForMultipleObjects() to make the same duetime adjustment, since they have the same rules regarding timeout values.
- Cosmetic: change name of 'timeout' variable in KeWaitForSingleObject() and KeWaitForMultipleObjects() to 'duetime' to avoid senseless (though harmless) overlap with timeout() function name.
With these fixes, I can get the 5211 card to associate properly with my adhoc net using driver AR5211.SYS version 2.4.1.6.
|
126706 |
07-Mar-2004 |
wpaul |
Add preliminary support for PCMCIA devices in addition to PCI/cardbus. if_ndis.c has been split into if_ndis_pci.c and if_ndis_pccard.c. The ndiscvt(8) utility should be able to parse device info for PCMCIA devices now. The ndis_alloc_amem() has moved from kern_ndis.c to if_ndis_pccard.c so that kern_ndis.c no longer depends on pccard.
NOTE: this stuff is not guaranteed to work 100% correctly yet. So far I have been able to load/init my PCMCIA Cisco Aironet 340 card, but it crashes in the interrupt handler. The existing support for PCI/cardbus devices should still work as before.
|
126674 |
05-Mar-2004 |
jhb |
kthread_exit() no longer requires Giant, so don't force callers to acquire Giant just to call kthread_exit().
Requested by: many
|
126620 |
04-Mar-2004 |
wpaul |
- 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.
|
126568 |
04-Mar-2004 |
wpaul |
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.
|
126559 |
03-Mar-2004 |
wpaul |
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 opt_ddb.h.
|
125950 |
17-Feb-2004 |
wpaul |
Add vector for memmove() (currently aliased to memcpy()) a implement ExInterlockedAddLargeStatistic().
|
125860 |
16-Feb-2004 |
wpaul |
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.
|
125814 |
14-Feb-2004 |
wpaul |
Fix a problem with the way we schedule work on the NDIS worker threads. The Am1771 driver will sometimes do the following:
- Some thread-> NdisScheduleWorkItem(some work) - Worker thread -> do some work, KeWaitForSingleObject(some event) - Some other thread -> NdisScheduleWorkItem(some other work)
When the second call to NdisScheduleWorkItem() occurs, the NDIS worker thread (in our case ndis taskqueue) is suspended in KeWaitForSingleObject() and waiting for an event to be signaled. This is different from when the worker thread is idle and waiting on NdisScheduleWorkItem() to send it more jobs. However, the ndis_sched() function in kern_ndis.c always calls kthread_resume() when queueing a new job. Normally this would be ok, but here this causes KeWaitForSingleObject() to return prematurely, which is not what we want.
To fix this, the NDIS threads created by kern_ndis.c maintain a state variable to indicate whether they are running (scanning the job list and executing jobs) or sleeping (blocked on kthread_suspend() in ndis_runq()), and ndis_sched() will only call kthread_resume() if the thread is in the sleeping state.
Note that we can't just check to see if the thread is on the run queue: in both cases, the thread is sleeping, but it's sleeping for different reasons.
This stops the Am1771 driver from emitting various "NDIS ERROR" messages and fixes some cases where it crashes.
|
125723 |
11-Feb-2004 |
wpaul |
Correct instance of *timeout that should have been timeout.
Noticed by: mlaier
|
125718 |
11-Feb-2004 |
wpaul |
Add yet more bulletproofing. This is to guard against the case that ndis_init_nic() works one during attach, but fails later. Many things will blow up if ndis_init_nic() fails and we aren't careful.
|
125676 |
10-Feb-2004 |
wpaul |
Add some bulletproofing: don't allow the ndis_get_info() or ndis_set_info() routines to do anything except return error if the miniport adapter context is not set (meaning we either having init'ed the driver yet, or the initialization failed).
Also, be sure to NULL out the adapter context along with the miniport characteristics pointers if calling the MiniportInitialize() method fails.
|
125628 |
09-Feb-2004 |
wpaul |
Add stub implementations of KfLowerIrql() and KfRaiseIrql() (both of which are _fastcall).
|
125599 |
08-Feb-2004 |
wpaul |
Make NdisMMapIoSpace() guard against NULL/uninitialized resource pointers too.
|
125598 |
08-Feb-2004 |
wpaul |
Make NdisMMapIoSpace() handle the case where a device has both mem and altmem ranges mapped.
|
125582 |
07-Feb-2004 |
wpaul |
Argh. kthread_suspend() when in P_KTHREAD context, tsleep() when not, not the other way around.
|
125577 |
07-Feb-2004 |
wpaul |
Correct an intance of mtx_pool_lock() that should have been mtx_pool_unlock().
|
125551 |
07-Feb-2004 |
wpaul |
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 routines:
PsCreateSystemThread() PsTerminateSystemThread() KeInitializeEvent() KeSetEvent() KeResetEvent() KeInitializeMutex() KeReleaseMutex() KeWaitForSingleObject() KeWaitForMultipleObjects() IoGetDeviceProperty()
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.
|
125413 |
04-Feb-2004 |
wpaul |
Correct/improve the implementation of NdisMAllocateSharedMemoryAsync(). Since we have a worker thread now, we can actually do the allocation asynchronously in that thread's context. Also, we need to return a status value: if we're unable to queue up the async allocation, we return NDIS_STATUS_FAILURE, otherwise we return NDIS_STATUS_PENDING to indicate the allocation has been queued and will occur later.
This replaces the kludge where we just invoked the callback routine right away in the current context.
|
125377 |
03-Feb-2004 |
wpaul |
Implement support for single packet sends. The Intel Centrino driver that Asus provides on its CDs has both a MiniportSend() routine and a MiniportSendPackets() function. The Microsoft NDIS docs say that if a driver has both, only the MiniportSendPackets() routine will be used. Although I think I implemented the support correctly, calling the MiniportSend() routine seems to result in no packets going out on the air, even though no error status is returned. The MiniportSendPackets() function does work though, so at least in this case it doesn't matter.
In if_ndis.c:ndis_getstate_80211(), if ndis_get_assoc() returns an error, don't bother trying to obtain any other state since the calls may fail, or worse cause the underlying driver to crash.
(The above two changes make the Asus-supplied Centrino work.)
Also, when calling the OID_802_11_CONFIGURATION OID, remember to initialize the structure lengths correctly.
In subr_ndis.c:ndis_open_file(), set the current working directory to rootvnode if we're in a thread that doesn't have a current working directory set.
|
125069 |
27-Jan-2004 |
wpaul |
Implement NdisVirtualBufferAddress() and NdisVirtualBufferAddressSafe().
The RealTek 8180 driver seems to need this.
|
125057 |
26-Jan-2004 |
wpaul |
Reorganize the timer code a little and implement NdisInitializeTimer() and NdisCancelTimer(). NdisInitializeTimer() doesn't accept an NDIS miniport context argument, so we have to derive it from the timer function context (which is supposed to be the adapter private context). NdisCancelTimer is now an alias for NdisMCancelTimer().
Also add stubs for NdisMRegisterDevice() and NdisMDeregisterDevice(). These are no-ops for now, but will likely get fleshed in once I start working on the Am1771/Am1772 wireless driver.
|
125006 |
26-Jan-2004 |
wpaul |
Avoid possible panic on shutdown: if there are still some devices attached when shutting down, kill our kthreads, but don't destroy the mutex pool and uma zone resources since the driver shutdown routine may need them later.
|
124813 |
21-Jan-2004 |
wpaul |
Add structures and definitions for task offload (TCP/IP checksum, IPSec, TCP large send).
|
124809 |
21-Jan-2004 |
wpaul |
Make sure to trap failures correctly in ndis_get_info() and ndis_set_info().
|
124729 |
19-Jan-2004 |
wpaul |
Add WDM major/minor #defines.
|
124727 |
19-Jan-2004 |
wpaul |
Implement IofCompleteRequest() and IoIsWdmVersionAvailable(). Correct IofCallDriver(): it's fastcall, not stdcall. Add vector to vsprintf().
|
124725 |
19-Jan-2004 |
wpaul |
Implement atoi() and atol(). Some drivers appear to need these. Note that like most C library routines, these appear to be _cdecl in Windows.
|
124724 |
19-Jan-2004 |
wpaul |
Eliminate some code duplication: since ndis_runq() and ndis_intq() were basically the same function, compact them into a single loop which can be used for both threads.
|
124697 |
18-Jan-2004 |
wpaul |
Convert from using taskqueue_swi to using private kernel threads. The problem with using taskqueue_swi is that some of the things we defer into threads might block for up to several seconds. This is an unfriendly thing to do to taskqueue_swi, since it is assumed the taskqueue threads will execute fairly quickly once a task is submitted. Reorganized the locking in if_ndis.c in the process.
Cleaned up ndis_write_cfg() and ndis_decode_parm() a little.
|
124582 |
16-Jan-2004 |
obrien |
The ndis_kspin_lock type is called KSPIN_LOCK in MS-Windows. According to the Windows DDK header files, KSPIN_LOCK is defined like this: typedef ULONG_PTR KSPIN_LOCK;
From basetsd.h (SDK, Feb. 2003): typedef [public] unsigned __int3264 ULONG_PTR, *PULONG_PTR; typedef unsigned __int64 ULONG_PTR, *PULONG_PTR; typedef _W64 unsigned long ULONG_PTR, *PULONG_PTR;
The keyword __int3264 specifies an integral type that has the following properties: + It is 32-bit on 32-bit platforms + It is 64-bit on 64-bit platforms + It is 32-bit on the wire for backward compatibility. It gets truncated on the sending side and extended appropriately (signed or unsigned) on the receiving side.
Thus register_t seems the proper mapping onto FreeBSD for spin locks.
|
124576 |
15-Jan-2004 |
wpaul |
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.
|
124574 |
15-Jan-2004 |
obrien |
Create NDIS_BUS_SPACE_{IO,MEM} to abstract MD BUS_SPACE macros. Provide appropriate definitions for i386 and AMD64.
|
124541 |
15-Jan-2004 |
wpaul |
Implement NdisCopyFromPacketToPacket() and NdisCopyFromPacketToPacketSafe(). I only have one driver that references this routine (for the 3Com 3cR990) and it never gets called, but just in case, here it is.
|
124509 |
14-Jan-2004 |
wpaul |
mp_ncpus is always defined now, so no need to do an #ifdef SMP in ndis_cpu_cnt().
|
124504 |
13-Jan-2004 |
obrien |
AMD64 has a single MS-Win calling convention, so provide an empty __stdcall. Centralize the definition to make it easier to change.
|
124502 |
13-Jan-2004 |
obrien |
Use 'vm_offset_t' rather than 'u_int32_t'.
Tested on: AMD64 Reviewed by: wpaul
|
124501 |
13-Jan-2004 |
obrien |
AMD64 has a single MS-Win calling convention, so provide an empty __stdcall.
|
124463 |
13-Jan-2004 |
wpaul |
Implement some more unicode handling routines. This will hopefully bring us closer to being able to run the Intel PRO/Wireless 5000 driver.
|
124454 |
13-Jan-2004 |
wpaul |
Loosen up the range test in ndis_register_ioport(). Allow drivers to map ranges that are smaller than what our resource manager code knows is available, rather than requiring that they match exactly. This fixes a problem with the Intel PRO/1000 gigE driver: it wants to map a range of 32 I/O ports, even though some chips appear set up to decode a range of 64. With this fix, it loads and runs correctly.
|
124450 |
12-Jan-2004 |
wpaul |
Ugh. I am not having a good day. Remove debugging #ifdef that accidentally crept into the last commit.
|
124448 |
12-Jan-2004 |
wpaul |
Ugh. Last commit went horribly wrong. Back out changes to subr_ntoskrnl.c, make sure if_ndis.c really gets checked in this time.
|
124446 |
12-Jan-2004 |
wpaul |
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 ndis_intrtask().
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.
|
124409 |
12-Jan-2004 |
wpaul |
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.
|
124278 |
09-Jan-2004 |
wpaul |
The private data section of ndis_packets has a 'packet flags' byte which has two important flags in it: the 'allocated by NDIS' flag and the 'media specific info present' flag. There are two Windows macros for getting/setting media specific info fields within the ndis_packet structure which can behave improperly if these flags are not initialized correctly when a packet is allocated. It seems the correct thing to do is always set the NDIS_PACKET_ALLOCATED_BY_NDIS flag on all newly allocated packets.
This fixes the crashes with the Intel Centrino wireless driver. My sample card now seems to work correctly.
Also, fix a potential LOR involving ndis_txeof() in if_ndis.c.
|
124272 |
09-Jan-2004 |
wpaul |
Implement NdisOpenFile()/NdisCloseFile()/NdisMapFile()/NdisUnmapFile(). By default, we search for files in /compat/ndis. This can be changed with a systcl. These routines are used by some drivers which need to download firmware or microcode into their respective devices during initialization.
Also, remove extraneous newlines from the 'built-in' sysctl/registry variables.
|
124246 |
08-Jan-2004 |
wpaul |
Correct the definition of the ndis_miniport_interrupt structure: the ni_dpccountlock member is an ndis_kspin_lock, not an ndis_spin_lock (the latter is too big).
Run if_ndis.c:ndis_tick() via taskqueue_schedule(). Also run ndis_start() via taskqueue in certain circumstances.
Using these tweaks, I can now get the Broadcom BCM5701 NDIS driver to load and run. Unfortunately, the version I have seems to suffer from the same bug as the SMC 83820 driver, which is that it creates a spinlock during its DriverEntry() routine. I'm still debating the right way to deal with this.
|
124231 |
07-Jan-2004 |
wpaul |
Correct and simplify the implementation of RtlEqualUnicodeString().
|
124228 |
07-Jan-2004 |
wpaul |
It appears drivers may call NdisWriteErrorLogEntry() with locks held. However, if we need to translate a unicode message table message, ndis_unicode_to_ascii() might malloc() some memory, which causes a warning from witness. Avoid this by using some stack space to hold the translated message. (Also bounds check to make sure we don't overrun the stack buffer.)
|
124203 |
07-Jan-2004 |
wpaul |
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.)
|
124202 |
07-Jan-2004 |
wpaul |
In subr_ndis.c: correct ndis_interlock_inc() and ndis_interlock_dec() so we increment the right thing. (All work and not enough parens make Bill something something...) This makes the RealTek 8139C+ driver work correctly.
Also fix some mtx_lock_spin()s and mtx_unlock_spin()s that should have been just plain mtx_lock()s and mtx_unlock()s.
In kern_ndis.c: remove duplicate code from ndis_send_packets() and just call the senddone handler (ndis_txeof()).
|
124173 |
06-Jan-2004 |
wpaul |
Clean up pe_get_message(). Allow the caller to obtain the resource flag so that it can see if the message string is unicode or not and do the conversion itself rather than doing it in subr_pe.c. This prevents subr_pe.c from being dependent on subr_ndis.c.
|
124165 |
06-Jan-2004 |
wpaul |
- 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().
|
124135 |
04-Jan-2004 |
wpaul |
Modify if_ndis.c so that the MiniportISR function runs in ndis_intr() and MiniportHandleInterrupt() is fired off later via a task queue in ndis_intrtask(). This more accurately follows the NDIS interrupt handling model, where the ISR does a minimal amount of work in interrupt context and the handler is defered and run at a lower priority.
Create a separate ndis_intrmtx mutex just for the guarding the ISR.
Modify NdisSynchronizeWithInterrupt() to aquire the ndis_intrmtx mutex before invoking the synchronized procedure. (The purpose of this function is to provide mutual exclusion for code that shares variables with the ISR.)
Modify NdisMRegisterInterrupt() to save a pointer to the miniport block in the ndis_miniport_interrupt structure so that NdisSynchronizeWithInterrupt() can grab it later and derive ndis_intrmtx from it.
|
124122 |
04-Jan-2004 |
wpaul |
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.
|
124116 |
04-Jan-2004 |
wpaul |
In ndis_attach(), report the NDIS API level that the Windows miniport driver was compiled with.
Remove debug printf from ndis_assicn_pcirsc(). It doesn't serve much purpose.
Implement NdisMIndicateStatus() and NdisMIndicateStatusComplete() as functions in subr_ndis.c. In NDIS 4.0, they were functions. In NDIS 5.0 and later, they're just macros.
Allocate a few extra packets/buffers beyond what the driver asks for since sometimes it seems they can lie about how many they really need, and some extra stupid ones don't check to see if NdisAllocatePacket() and/or NdisAllocateBuffer() actually succeed.
|
124100 |
03-Jan-2004 |
wpaul |
In if_ndis.c:ndis_attach(), temporarily set the IFF_UP flag while calling the haltfunc. If an interrupt is triggered by the init or halt func, the IFF_UP flag must be set in order for us to be able to service it.
In kern_ndis.c: implement a handler for NdisMSendResourcesAvailable() (currently does nothing since we don't really need it).
In subr_ndis.c: - Correct ndis_init_string() and ndis_unicode_to_ansi(), which were both horribly broken. - Implement NdisImmediateReadPciSlotInformation() and NdisImmediateWritePciSlotInformation(). - Implement NdisBufferLength(). - Work around my first confirmed NDIS driver bug. The SMC 9462 gigE driver (natsemi 83820-based copper) incorrectly creates a spinlock in its DriverEntry() routine and then destroys it in its MiniportHalt() handler. This is wrong: spinlocks should be created in MiniportInit(). In a Windows environment, this is often not a problem because DriverEntry()/MiniportInit() are called once when the system boots and MiniportHalt() or the shutdown handler is called when the system halts.
With this stuff in place, this driver now seems to work:
ndis0: <SMC EZ Card 1000> port 0xe000-0xe0ff mem 0xda000000-0xda000fff irq 10 at device 9.0 on pci0 ndis0: assign PCI resources... ndis_open_file("FLASH9.hex", 18446744073709551615) ndis0: Ethernet address: 00:04:e2:0e:d3:f0
|
124097 |
03-Jan-2004 |
wpaul |
subr_hal.c: implement WRITE_PORT_BUFFER_xxx() and READ_PORT_BUFFER_xxx() subr_ndis.c: implement NdisDprAllocatePacket() and NdisDprFreePacket() (which are aliased to NdisAllocatePacket() and NdisFreePacket()), and bump the value we return in ndis_mapreg_cnt() to something ridiculously large, since some drivers apparently expect to be able to allocate way more than just 64.
These changes allow the Level 1 1000baseSX driver to work for the following card:
ndis0: <SMC TigerCard 1000 Adapter> port 0xe000-0xe0ff mem 0xda004000-0xda0043ff irq 10 at device 9.0 on pci0 ndis0: Ethernet address: 00:e0:29:6f:cc:04
This is already supported by the lge(4) driver, but I decided to take a try at making the Windows driver that came with it work too, since I still had the floppy diskette for it lying around.
|
124094 |
03-Jan-2004 |
wpaul |
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;
ntoskrnl:
KefAcquireSpinLockAtDpcLevel KefReleaseSpinLockFromDpcLevel MmMapLockedPages InterlockedDecrement InterlockedIncrement IoFreeMdl KeInitializeSpinLock
HAL:
KfReleaseSpinLock KeGetCurrentIrql KfAcquireSpinLock
Lastly, correct spelling of "_aullshr" in the ntoskrnl functable.
|
124060 |
02-Jan-2004 |
wpaul |
Clean up ndiscvt a bit (leaving out the -i flag didn't work) and add copyrights to the inf parser files.
Add a -n flag to ndiscvt to allow the user to override the default device name of NDIS devices. Instead of "ndis0, ndis1, etc..." you can have "foo0, foo1, etc..." This allows you to have more than one kind of NDIS device in the kernel at the same time.
Convert from printf() to device_printf() in if_ndis.c, kern_ndis.c and subr_ndis.c.
Create UMA zones for ndis_packet and ndis_buffer structs allocated on transmit. The zones are created and destroyed in the modevent handler in kern_ndis.c.
printf() and UMA changes submitted by green@freebsd.org
|
124014 |
31-Dec-2003 |
wpaul |
- 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().
|
124005 |
30-Dec-2003 |
wpaul |
- Add new 802.11 OID information obtained from NDIS 5.1 update to ndis_var.h - In kern_ndis.c:ndis_send_packets(), avoid dereferencing NULL pointers created when the driver's send routine immediately calls the txeof handler (which releases the packets for us anyway). - In if_ndis.c:ndis_80211_setstate(), implement WEP support.
|
123976 |
29-Dec-2003 |
wpaul |
Rework resource allocation. Replace the "feel around like a blind man" method with something a little more intelligent: use BUS_GET_RESOURCE_LIST() to run through all resources allocated to us and map them as needed. This way we know exactly what resources need to be mapped and what their RIDs are without having to guess. This simplifies both ndis_attach() and ndis_convert_res(), and eliminates the unfriendly "ndisX: couldn't map <foo>" messages that are sometimes emitted during driver load.
|
123941 |
28-Dec-2003 |
wpaul |
Implement NdisInitUnicodeString().
|
123940 |
28-Dec-2003 |
wpaul |
Remove the sanity test in ndis_adjust_buflen(). I'm not sure what the nb_size field in an ndis_buffer is meant to represent, but it does not represent the original allocation size, so the sanity check doesn't make any sense now that we're using the Windows-mandated initialization method.
Among other things, this makes the following card work with the NDISulator:
ndis0: <NETGEAR PA301 Phoneline10X PCI Adapter> mem 0xda004000-0xda004fff irq 10 at device 9.0 on pci0
This is that notoriously undocumented 10Mbps HomePNA Broadcom chipset that people wanted support for many moons ago. Sadly, the only other HomePNA NIC I have handy is a 1Mbps device, so I can't actually do any 10Mbps performance tests, but it talks to my 1Mbps ADMtek card just fine.
|
123858 |
26-Dec-2003 |
wpaul |
Attempt to handle the status field in the ndis_packet oob area correctly.
For received packets, an status of NDIS_STATUS_RESOURCES means we need to copy the packet data and return the ndis_packet to the driver immediatel. NDIS_STATUS_SUCCESS means we get to hold onto the packet, but we have to set the status to NDIS_STATUS_PENDING so the driver knows we're going to hang onto it for a while.
For transmit packets, NDIS_STATUS_PENDING means the driver will asynchronously return the packet to us via the ndis_txeof() routine, and NDIS_STATUS_SUCCESS means the driver sent the frame, and NDIS (i.e. the OS) retains ownership of the packet and can free it right away.
|
123848 |
26-Dec-2003 |
wpaul |
Back out the last batch of changes until I have a chance to properly evaluate them. Whatever they're meant to do, they're doing it wrong.
Also:
- Clean up last bits of NULL fallout in subr_pe - Don't let ndis_ifmedia_sts() do anything if the IFF_UP flag isn't set - Implement NdisSystemProcessorCount() and NdisQueryMapRegisterCount().
|
123846 |
26-Dec-2003 |
green |
Don't call the miniport driver's releasepacket function unless the packet being freed has NDIS_STATUS_PENDING in the status field of the OOB data. Finish implementing the "alternative" packet-releasing function so it doesn't crash.
For those that are curious about ndis0: <ORiNOCO 802.11abg ComboCard Gold>: 1123 packets transmitted, 1120 packets received, 0% packet loss round-trip min/avg/max/stddev = 3.837/6.146/13.919/1.925 ms
Not bad!
|
123832 |
25-Dec-2003 |
wpaul |
Give the timer API one last overhaul: this time, use the new callout API instead of the old timeout/untimeout mechanism.
|
123826 |
25-Dec-2003 |
wpaul |
Avoid using any of the ndis_packet/ndis_packet_private fields for mbuf<->packet housekeeping. Instead, add a couple of extra fields to the end of ndis_packet. These should be invisible to the Windows driver module.
This also lets me get rid of a little bit of evil from ndis_ptom() (frobbing of the ext_buf field instead of relying on the MEXTADD() macro).
|
123822 |
25-Dec-2003 |
wpaul |
- 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 status.
Submitted by: Brian Feldman <green@freebsd.org>
|
123821 |
24-Dec-2003 |
wpaul |
- Fix some compiler warnings in subr_pe.c - Add explicit cardbus attachment in if_ndis.c - Clean up after moving bus_setup_intr() in ndis_attach(). - When setting an ssid, program an empty ssid as a 1-byte string with a single 0 byte. The Microsoft documentation says this is how you're supposed to tell the NIC to attach to 'any' ssid. - Keep trace of callout handles for timers externally from the ndis_miniport_timer structs, and run through and clobber them all after invoking the haltfunc just in case the driver left one running. (We need to make sure all timers are cancelled on driver unload.) - Handle the 'cancelled' argument in ndis_cancel_timer() correctly.
|
123810 |
24-Dec-2003 |
alfred |
change NULL to 0 to silence warning.
|
123778 |
23-Dec-2003 |
wpaul |
Correct the definitions for NDIS_80211_NET_INFRA_IBSS and NDIS_80211_NET_INFRA_BSS: I accidentally reversed them during transcription from the Microsoft headers. Note that the driver will default to BSS mode, and you need to specify 'mediaopt adhoc' to get it into IBSS mode.
|
123757 |
23-Dec-2003 |
wpaul |
Re-do the handling of ndis_buffers. The NDIS_BUFFER structure is supposed to be opaque to the driver, however it is exposed through several macros which expect certain behavior. In my original implementation, I used the mappedsystemva member of the structure to hold a pointer to the buffer and bytecount to hold the length. It turns out you must use the startva pointer to point to the page containing the start of the buffer and set byteoffset to the offset within the page where the buffer starts. So, for a buffer with address 'baseva,' startva is baseva & ~(PAGE_SIZE -1) and byteoffset is baseva & (PAGE_SIZE -1). We have to maintain this convention everywhere that ndis_buffers are used.
Fortunately, Microsoft defines some macros for initializing and manipulating NDIS_BUFFER structures in ntddk.h. I adapted some of them for use here and used them where appropriate.
This fixes the discrepancy I observed between how RX'ed packet sizes were being reported in the Broadcom wireless driver and the sample ethernet drivers that I've tested. This should also help the Intel Centrino wireless driver work.
Also try to properly initialize the 802.11 BSS and IBSS channels. (Sadly, the channel value is meaningless since there's no way in the existing NDIS API to get/set the channel, but this should take care of any 'invalid channel (NULL)' messages printed on the console.
|
123723 |
22-Dec-2003 |
wpaul |
Some minor touchups:
In NdisQueryBuffer() and NdisQueryBufferSafe(), the vaddr argument is optional, so test it before trying to dereference it.
Also correct NdisGetFirstBufferFromPacket()/NdisGetFirstBufferFromPacketSafe(): we need to use nb_mappedsystemva from the buffer, not nb_systemva.
|
123721 |
22-Dec-2003 |
wpaul |
Now that I finally have power back, implement a couple more NDIS API routines: NdisUnchainBufferAtBack(), NdisGetFirstBufferFromPacketSafe() and NdisGetFirstBufferFromPacket(). This should bring us a little closer to getting the Intel centrino wireless NIC to work.
Note: I have not actually tested these additions since I don't have a driver that calls them, however they're pretty simple, and one of them is taken pretty much directly from the Windows ndis.h header file, so I'm fairly confident they work, but disclaimers apply.
|
123695 |
21-Dec-2003 |
wpaul |
Big round of updates:
- Make ndis_get_info()/ndis_set_info() sleep on the setdone/getdone routines if they get back NDIS_STATUS_PENDING.
- Add a bunch of net80211 support so that 802.11 cards can be twiddled with ifconfig. This still needs more work and is not guaranteed to work for everyone. It works on my 802.11b/g card anyway.
The problem here is Microsoft doesn't provide a good way to a) learn all the rates that a card supports (if it has more than 8, you're kinda hosed) and b) doesn't provide a good way to distinguish between 802.11b, 802.11b/g an 802.11a/b/g cards, so you sort of have to guess.
Setting the SSID and switching between infrastructure/adhoc modes should work. WEP still needs to be implemented. I can't find any API for getting/setting the channel other than the registry/sysctl keys.
|
123620 |
18-Dec-2003 |
wpaul |
Deal with the duplicate sysctl leaf problem. A .inf file may contain definitions for more than one device (usually differentiated by the PCI subvendor/subdevice ID). Each device also has its own tree of registry keys. In some cases, each device has the same keys, but sometimes each device has a unique tree but with overlap. Originally, I just had ndiscvt(8) dump out all the keys it could find, and we would try to apply them to every device we could find. Now, each key has an index number that matches it to a device in the device ID list. This lets us create just the keys that apply to a particular device.
I also added an extra field to the device list to hold the subvendor and subdevice ID.
Some devices are generic, i.e. there is no subsystem definition. If we have a device that doesn't match a specific subsystem value and we have a generic entry, we use the generic entry.
|
123573 |
16-Dec-2003 |
wpaul |
Implement NdisGetBufferPhysicalArraySize(), which apparently is a synonym for NDIS_BUFFER_TO_SPAN_PAGES().
|
123536 |
14-Dec-2003 |
wpaul |
Whups... remove some debug code that accidentally crept in.
|
123535 |
14-Dec-2003 |
wpaul |
Rework mbuf<->ndis_packet/ndis_packet<->mbuf translation a little to make it more robust. This should fix problems with crashes under heavy traffic loads that have been reported. Also add a 'query done' callback handler to satisfy the e100bex.sys sample Intel driver.
|
123526 |
14-Dec-2003 |
wpaul |
Implement a few new NDIS routines: NdisInitAnsiString(), NdisAnsiStringToUnicodeString(), NdisWriteConfiguration().
Also add stubs for NdisMGetDeviceProperty(), NdisTerminateWrapper(), NdisOpenConfigurationKeyByName(), NdisOpenConfigurationKeyByIndex() and NdisMGetDeviceProperty().
|
123512 |
13-Dec-2003 |
wpaul |
Correct the implementation of NDIS_BUFFER_TO_SPAN_PAGES().
|
123507 |
13-Dec-2003 |
wpaul |
subr_ndis.c: - fix ndis_time() so that it returns a time based on the proper epoch (wacky though it may be) - implement NdisInitializeString() and NdisFreeString(), and add stub for NdisMRemoveMiniport()
ntoskrnl_var.h: - add missing member to the general_lookaside struct (gl_listentry)
subr_ntoskrnl.c: - Fix arguments to the interlocked push/pop routines: 'head' is an slist_header *, not an slist_entry * - Kludge up _fastcall support for the push/pop routines. The _fastcall convention is similar to _stdcall, except the first two available DWORD-sized arguments are passed in %ecx and %edx, respectively. One kludge for this __attribute__ ((regparm(3))), however this isn't entirely right, as it assumes %eax, %ecx and %edx will be used (regparm(2) assumes %eax and %edx). Another kludge is to declare the two fastcall-ed args as local register variables and explicitly assign them to %ecx and %edx, but experimentation showed that gcc would not guard %ecx and %edx against being clobbered. Thus, I came up with a 3rd kludge, which is to use some inline assembly of the form:
void *arg1; void *arg2;
__asm__("movl %%ecx, %%ecx" : "=c" (arg1)); __asm__("movl %%edx, %%edx" : "=d" (arg2));
This lets gcc know that we're going to reference %ecx and %edx and that it should make an effort not to let it get trampled. This wastes an instruction (movl %reg, %reg is a no-op) but insures proper behavior. It's possible there's a better way to do this though: this is the first time I've used inline assembler in this fashion.
The above fixes to ntoskrnl_var.h an subr_ntoskrnl.c make lookaside lists work for the two drivers I have that use them, one of which is an NDIS 5.0 miniport and another which is 5.1.
|
123504 |
12-Dec-2003 |
wpaul |
Implement some more NDIS and ntoskrnl API calls:
subr_ndis.c: NdisGetCurrentSystemTime() which, according to the Microsoft documentation returns "the number of 100 nanosecond intervals since January 1, 1601." I have no idea what's so special about that epoch or why they chose 100 nanosecond ticks. I don't know the proper offset to convert nanotime() from the UNIX epoch to January 1, 1601, so for now I'm just doing the unit convertion to 100s of nanoseconds.
subr_ntoskrnl.c: memcpy(), memset(), ExInterlockedPopEntrySList(), ExInterlockedPushEntrySList().
The latter two are different from InterlockedPopEntrySList() and InterlockedPushEntrySList() in that they accept a spinlock to hold while executing, whereas the non-Ex routines use a lock internal to ntoskrnl. I also modified ExInitializePagedLookasideList() and ExInitializeNPagedLookasideList() to initialize mutex locks within the lookaside structures. It seems that in NDIS 5.0, the lookaside allocate/free routines ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(), which require the use of the per-lookaside spinlock, whereas in NDIS 5.1, the per-lookaside spinlock is deprecated. We need to support both cases.
Note that I appear to be doing something wrong with ExInterlockedPopEntrySList() and ExInterlockedPushEntrySList(): they don't appear to obtain proper pointers to their arguments, so I'm probably doing something wrong in terms of their calling convention (they're declared to be FASTCALL in Widnows, and I'm not sure what that means for gcc). It happens that in my stub lookaside implementation, they don't need to do any work anyway, so for now I've hacked them to always return NULL, which avoids corrupting the stack. I need to do this right though.
|
123488 |
12-Dec-2003 |
wpaul |
Correct the behavior of ndis_adjust_buflen(): the NDIS spec says it's an error to set the buffer bytecount to anything larger than the buffer's original allocation size, but anything less than that is ok.
Also, in ndis_ptom(), use the same logic: if the bytecount is larger than the allocation size, consider the bytecount invalid and the allocation size as the packet fragment length (m_len) instead of the bytecount.
This corrects a consistency problem between the Broadcom wireless driver and some of the ethernet drivers I've tested: the ethernet drivers all report the packet frag sizes in buf->nb_bytecount, but the Broadcom wireless driver reports them in buf->nb_size. This seems like a bug to me, but it clearly must work in Windows, so we have to deal with it here too.
|
123485 |
12-Dec-2003 |
wpaul |
In NDIS 5.1 miniport drivers, the shutdown handler function pointer is provided to NDIS via the the miniport characteristics structure supplied in the call to NdisMRegisterMiniport(). But in NDIS 5.0 and earlier, you had to call NdisMRegisterAdapterShutdownHandler() and supply both a function pointer and context pointer.
We try to handle both cases in ndis_shutdown_nic(). If the driver registered a shutdown routine and a context,then used that context, otherwise pass it the adapter context from NdisMSetAttributesEx().
This fixes a panic on shutdown with the sample Intel 82559 e100bex.sys driver from the Windows DDK. function pointer
|
123474 |
11-Dec-2003 |
wpaul |
Commit the first cut of Project Evil, also known as the NDISulator.
Yes, it's what you think it is. Yes, you should run away now.
This is a special compatibility module for allowing Windows NDIS miniport network drivers to be used with FreeBSD/x86. This provides _binary_ NDIS compatibility (not source): you can run NDIS driver code, but you can't build it. There are three main parts:
sys/compat/ndis: the NDIS compat API, which provides binary compatibility functions for many routines in NDIS.SYS, HAL.dll and ntoskrnl.exe in Windows (these are the three modules that most NDIS miniport drivers use). The compat module also contains a small PE relocator/dynalinker which relocates the Windows .SYS image and then patches in our native routines.
sys/dev/if_ndis: the if_ndis driver wrapper. This module makes use of the ndis compat API and can be compiled with a specially prepared binary image file (ndis_driver_data.h) containing the Windows .SYS image and registry key information parsed out of the accompanying .INF file. Once if_ndis.ko is built, it can be loaded and unloaded just like a native FreeBSD kenrel module.
usr.sbin/ndiscvt: a special utility that converts foo.sys and foo.inf into an ndis_driver_data.h file that can be compiled into if_ndis.o. Contains an .inf file parser graciously provided by Matt Dodd (and mercilessly hacked upon by me) that strips out device ID info and registry key info from a .INF file and packages it up with a binary image array. The ndiscvt(8) utility also does some manipulation of the segments within the .sys file to make life easier for the kernel loader. (Doing the manipulation here saves the kernel code from having to move things around later, which would waste memory.)
ndiscvt is only built for the i386 arch. Only files.i386 has been updated, and none of this is turned on in GENERIC. It should probably work on pc98. I have no idea about amd64 or ia64 at this point.
This is still a work in progress. I estimate it's about %85 done, but I want it under CVS control so I can track subsequent changes. It has been tested with exactly three drivers: the LinkSys LNE100TX v4 driver (Lne100v4.sys), the sample Intel 82559 driver from the Windows DDK (e100bex.sys) and the Broadcom BCM43xx wireless driver (bcmwl5.sys). It still needs to have a net80211 stuff added to it. To use it, you would do something like this:
# cd /sys/modules/ndis # make; make load # cd /sys/modules/if_ndis # ndiscvt -i /path/to/foo.inf -s /path/to/foo.sys -o ndis_driver_data.h # make; make load # sysctl -a | grep ndis
All registry keys are mapped to sysctl nodes. Sometimes drivers refer to registry keys that aren't mentioned in foo.inf. If this happens, the NDIS API module creates sysctl nodes for these keys on the fly so you can tweak them.
An example usage of the Broadcom wireless driver would be:
# sysctl hw.ndis0.EnableAutoConnect=1 # sysctl hw.ndis0.SSID="MY_SSID" # sysctl hw.ndis0.NetworkType=0 (0 for bss, 1 for adhoc) # ifconfig ndis0 <my ipaddr> netmask 0xffffff00 up
Things to be done:
- get rid of debug messages - add in ndis80211 support - defer transmissions until after a status update with NDIS_STATUS_CONNECTED occurs - Create smarter lookaside list support - Split off if_ndis_pci.c and if_ndis_pccard.c attachments - Make sure PCMCIA support works - Fix ndiscvt to properly parse PCMCIA device IDs from INF files - write ndisapi.9 man page
|