summaryrefslogtreecommitdiffstats
path: root/sys/dev/if_ndis
diff options
context:
space:
mode:
authorwpaul <wpaul@FreeBSD.org>2005-04-11 02:02:35 +0000
committerwpaul <wpaul@FreeBSD.org>2005-04-11 02:02:35 +0000
commita3b2d3191d684cc192012aa160695992e980f7fc (patch)
treec9baad954353fef64e8c9153b1fbd740ba9a5d42 /sys/dev/if_ndis
parentdff27787ebafbf9cb586beef441c793c09833c53 (diff)
downloadFreeBSD-src-a3b2d3191d684cc192012aa160695992e980f7fc.zip
FreeBSD-src-a3b2d3191d684cc192012aa160695992e980f7fc.tar.gz
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.
Diffstat (limited to 'sys/dev/if_ndis')
-rw-r--r--sys/dev/if_ndis/if_ndis.c43
1 files changed, 26 insertions, 17 deletions
diff --git a/sys/dev/if_ndis/if_ndis.c b/sys/dev/if_ndis/if_ndis.c
index 57dd266..45da8c9 100644
--- a/sys/dev/if_ndis/if_ndis.c
+++ b/sys/dev/if_ndis/if_ndis.c
@@ -94,13 +94,10 @@ void ndis_shutdown (device_t);
int ndisdrv_modevent (module_t, int, void *);
-static __stdcall void ndis_txeof (ndis_handle,
- ndis_packet *, ndis_status);
-static __stdcall void ndis_rxeof (ndis_handle,
- ndis_packet **, uint32_t);
-static __stdcall void ndis_linksts (ndis_handle,
- ndis_status, void *, uint32_t);
-static __stdcall void ndis_linksts_done (ndis_handle);
+static void ndis_txeof (ndis_handle, ndis_packet *, ndis_status);
+static void ndis_rxeof (ndis_handle, ndis_packet **, uint32_t);
+static void ndis_linksts (ndis_handle, ndis_status, void *, uint32_t);
+static void ndis_linksts_done (ndis_handle);
/* We need to wrap these functions for amd64. */
@@ -157,12 +154,16 @@ ndisdrv_modevent(mod, cmd, arg)
ndisdrv_loaded++;
if (ndisdrv_loaded > 1)
break;
- windrv_load(mod, (vm_offset_t)drv_data, 0);
- windrv_wrap((funcptr)ndis_rxeof, &ndis_rxeof_wrap);
- windrv_wrap((funcptr)ndis_txeof, &ndis_txeof_wrap);
- windrv_wrap((funcptr)ndis_linksts, &ndis_linksts_wrap);
+ if (windrv_load(mod, (vm_offset_t)drv_data, 0))
+ return(EINVAL);
+ windrv_wrap((funcptr)ndis_rxeof, &ndis_rxeof_wrap,
+ 3, WINDRV_WRAP_STDCALL);
+ windrv_wrap((funcptr)ndis_txeof, &ndis_txeof_wrap,
+ 3, WINDRV_WRAP_STDCALL);
+ windrv_wrap((funcptr)ndis_linksts, &ndis_linksts_wrap,
+ 4, WINDRV_WRAP_STDCALL);
windrv_wrap((funcptr)ndis_linksts_done,
- &ndis_linksts_done_wrap);
+ &ndis_linksts_done_wrap, 1, WINDRV_WRAP_STDCALL);
break;
case MOD_UNLOAD:
ndisdrv_loaded--;
@@ -493,7 +494,15 @@ ndis_attach(dev)
*/
img = drv_data;
+
drv = windrv_lookup((vm_offset_t)img, NULL);
+
+ if (drv == NULL) {
+ device_printf(dev, "failed to find driver_object!\n");
+ error = ENXIO;
+ goto fail;
+ }
+
if (NdisAddDevice(drv, pdo) != STATUS_SUCCESS) {
device_printf(dev, "failed to create FDO!\n");
error = ENXIO;
@@ -950,7 +959,7 @@ ndis_resume(dev)
* copy the packet data into local storage and let the driver keep the
* packet.
*/
-__stdcall static void
+static void
ndis_rxeof(adapter, packets, pktcnt)
ndis_handle adapter;
ndis_packet **packets;
@@ -1030,7 +1039,7 @@ ndis_rxeof(adapter, packets, pktcnt)
* A frame was downloaded to the chip. It's safe for us to clean up
* the list buffers.
*/
-__stdcall static void
+static void
ndis_txeof(adapter, packet, status)
ndis_handle adapter;
ndis_packet *packet;
@@ -1072,7 +1081,7 @@ ndis_txeof(adapter, packet, status)
return;
}
-__stdcall static void
+static void
ndis_linksts(adapter, status, sbuf, slen)
ndis_handle adapter;
ndis_status status;
@@ -1090,7 +1099,7 @@ ndis_linksts(adapter, status, sbuf, slen)
return;
}
-__stdcall static void
+static void
ndis_linksts_done(adapter)
ndis_handle adapter;
{
@@ -1178,7 +1187,7 @@ ndis_ticktask(xsc)
void *xsc;
{
struct ndis_softc *sc;
- __stdcall ndis_checkforhang_handler hangfunc;
+ ndis_checkforhang_handler hangfunc;
uint8_t rval;
ndis_media_state linkstate;
int error, len;
OpenPOWER on IntegriCloud