diff options
-rw-r--r-- | sys/compat/ndis/hal_var.h | 8 | ||||
-rw-r--r-- | sys/compat/ndis/kern_ndis.c | 113 | ||||
-rw-r--r-- | sys/compat/ndis/ndis_var.h | 5 | ||||
-rw-r--r-- | sys/compat/ndis/ntoskrnl_var.h | 39 | ||||
-rw-r--r-- | sys/compat/ndis/pe_var.h | 45 | ||||
-rw-r--r-- | sys/compat/ndis/subr_hal.c | 137 | ||||
-rw-r--r-- | sys/compat/ndis/subr_ndis.c | 89 | ||||
-rw-r--r-- | sys/compat/ndis/subr_ntoskrnl.c | 141 | ||||
-rw-r--r-- | sys/dev/if_ndis/if_ndis.c | 86 | ||||
-rw-r--r-- | sys/dev/if_ndis/if_ndisvar.h | 11 |
10 files changed, 468 insertions, 206 deletions
diff --git a/sys/compat/ndis/hal_var.h b/sys/compat/ndis/hal_var.h index a8be257..64a209f 100644 --- a/sys/compat/ndis/hal_var.h +++ b/sys/compat/ndis/hal_var.h @@ -45,4 +45,12 @@ extern image_patch_table hal_functbl[]; +__BEGIN_DECLS +__stdcall extern uint8_t hal_lock(/*kspin_lock * */void); +__stdcall extern void hal_unlock(/*kspin_lock *, uint8_t*/void); +__stdcall extern uint8_t hal_raise_irql(/*uint8_t*/ void); +__stdcall extern void hal_lower_irql(/*uint8_t*/ void); +__stdcall extern uint8_t hal_irql(void); +__END_DECLS + #endif /* _HAL_VAR_H_ */ diff --git a/sys/compat/ndis/kern_ndis.c b/sys/compat/ndis/kern_ndis.c index cd928dc..733e0d3 100644 --- a/sys/compat/ndis/kern_ndis.c +++ b/sys/compat/ndis/kern_ndis.c @@ -106,9 +106,8 @@ static int ndis_enlarge_thrqueue(int); static int ndis_shrink_thrqueue(int); static void ndis_runq(void *); -extern struct mtx_pool *ndis_mtxpool; static uma_zone_t ndis_packet_zone, ndis_buffer_zone; -struct mtx *ndis_thr_mtx; +struct mtx ndis_thr_mtx; static STAILQ_HEAD(ndisqhead, ndis_req) ndis_ttodo; struct ndisqhead ndis_itodo; struct ndisqhead ndis_free; @@ -207,23 +206,25 @@ ndis_runq(arg) p = arg; while (1) { - kthread_suspend(p->np_p, 0); + + /* Sleep, but preserve our original priority. */ + ndis_thsuspend(p->np_p, 0); /* Look for any jobs on the work queue. */ - mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); + mtx_lock(&ndis_thr_mtx); p->np_state = NDIS_PSTATE_RUNNING; while(STAILQ_FIRST(p->np_q) != NULL) { r = STAILQ_FIRST(p->np_q); STAILQ_REMOVE_HEAD(p->np_q, link); - mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); + mtx_unlock(&ndis_thr_mtx); /* Do the work. */ if (r->nr_func != NULL) (*r->nr_func)(r->nr_arg); - mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); + mtx_lock(&ndis_thr_mtx); STAILQ_INSERT_HEAD(&ndis_free, r, link); /* Check for a shutdown request */ @@ -232,7 +233,7 @@ ndis_runq(arg) die = r; } p->np_state = NDIS_PSTATE_SLEEPING; - mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); + mtx_unlock(&ndis_thr_mtx); /* Bail if we were told to shut down. */ @@ -242,6 +243,7 @@ ndis_runq(arg) wakeup(die); kthread_exit(0); + return; /* notreached */ } static int @@ -250,7 +252,9 @@ ndis_create_kthreads() struct ndis_req *r; int i, error = 0; - ndis_thr_mtx = mtx_pool_alloc(ndis_mtxpool); + mtx_init(&ndis_thr_mtx, "NDIS thread lock", + MTX_NDIS_LOCK, MTX_DEF); + STAILQ_INIT(&ndis_ttodo); STAILQ_INIT(&ndis_itodo); STAILQ_INIT(&ndis_free); @@ -308,6 +312,8 @@ ndis_destroy_kthreads() free(r, M_DEVBUF); } + mtx_destroy(&ndis_thr_mtx); + return; } @@ -329,16 +335,16 @@ ndis_stop_thread(t) /* Create and post a special 'exit' job. */ - mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); + mtx_lock(&ndis_thr_mtx); r = STAILQ_FIRST(&ndis_free); STAILQ_REMOVE_HEAD(&ndis_free, link); r->nr_func = NULL; r->nr_arg = NULL; r->nr_exit = TRUE; STAILQ_INSERT_TAIL(q, r, link); - mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); + mtx_unlock(&ndis_thr_mtx); - kthread_resume(p); + ndis_thresume(p); /* wait for thread exit */ @@ -346,12 +352,12 @@ ndis_stop_thread(t) /* Now empty the job list. */ - mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); + mtx_lock(&ndis_thr_mtx); while ((r = STAILQ_FIRST(q)) != NULL) { STAILQ_REMOVE_HEAD(q, link); STAILQ_INSERT_HEAD(&ndis_free, r, link); } - mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); + mtx_unlock(&ndis_thr_mtx); return; } @@ -367,10 +373,10 @@ ndis_enlarge_thrqueue(cnt) r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK); if (r == NULL) return(ENOMEM); - mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); + mtx_lock(&ndis_thr_mtx); STAILQ_INSERT_HEAD(&ndis_free, r, link); ndis_jobs++; - mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); + mtx_unlock(&ndis_thr_mtx); } return(0); @@ -384,15 +390,15 @@ ndis_shrink_thrqueue(cnt) int i; for (i = 0; i < cnt; i++) { - mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); + mtx_lock(&ndis_thr_mtx); r = STAILQ_FIRST(&ndis_free); if (r == NULL) { - mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); + mtx_unlock(&ndis_thr_mtx); return(ENOMEM); } STAILQ_REMOVE_HEAD(&ndis_free, link); ndis_jobs--; - mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); + mtx_unlock(&ndis_thr_mtx); free(r, M_DEVBUF); } @@ -417,17 +423,17 @@ ndis_unsched(func, arg, t) p = ndis_iproc.np_p; } - mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); + mtx_lock(&ndis_thr_mtx); STAILQ_FOREACH(r, q, link) { if (r->nr_func == func && r->nr_arg == arg) { STAILQ_REMOVE(q, r, ndis_req, link); STAILQ_INSERT_HEAD(&ndis_free, r, link); - mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); + mtx_unlock(&ndis_thr_mtx); return(0); } } - mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); + mtx_unlock(&ndis_thr_mtx); return(ENOENT); } @@ -451,20 +457,20 @@ ndis_sched(func, arg, t) p = ndis_iproc.np_p; } - mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); + mtx_lock(&ndis_thr_mtx); /* * Check to see if an instance of this job is already * pending. If so, don't bother queuing it again. */ STAILQ_FOREACH(r, q, link) { if (r->nr_func == func && r->nr_arg == arg) { - mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); + mtx_unlock(&ndis_thr_mtx); return(0); } } r = STAILQ_FIRST(&ndis_free); if (r == NULL) { - mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); + mtx_unlock(&ndis_thr_mtx); return(EAGAIN); } STAILQ_REMOVE_HEAD(&ndis_free, link); @@ -476,7 +482,7 @@ ndis_sched(func, arg, t) s = ndis_tproc.np_state; else s = ndis_iproc.np_state; - mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); + mtx_unlock(&ndis_thr_mtx); /* * Post the job, but only if the thread is actually blocked @@ -486,11 +492,32 @@ ndis_sched(func, arg, t) * it up until KeWaitForObject() gets woken up on its own. */ if (s == NDIS_PSTATE_SLEEPING) - kthread_resume(p); + ndis_thresume(p); return(0); } +int +ndis_thsuspend(p, timo) + struct proc *p; + int timo; +{ + int error; + + PROC_LOCK(p); + error = msleep(&p->p_siglist, &p->p_mtx, + curthread->td_priority|PDROP, "ndissp", timo); + return(error); +} + +void +ndis_thresume(p) + struct proc *p; +{ + wakeup(&p->p_siglist); + return; +} + __stdcall static void ndis_sendrsrcavail_func(adapter) ndis_handle adapter; @@ -706,6 +733,7 @@ ndis_return_packet(buf, arg) ndis_handle adapter; ndis_packet *p; __stdcall ndis_return_handler returnfunc; + uint8_t irql; if (arg == NULL) return; @@ -722,8 +750,11 @@ ndis_return_packet(buf, arg) sc = p->np_softc; returnfunc = sc->ndis_chars.nmc_return_packet_func; adapter = sc->ndis_block.nmb_miniportadapterctx; - if (adapter != NULL) + if (adapter != NULL) { + irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL); returnfunc(adapter, p); + FASTCALL1(hal_lower_irql, irql); + } return; } @@ -1035,6 +1066,7 @@ ndis_set_info(arg, oid, buf, buflen) __stdcall ndis_setinfo_handler setfunc; uint32_t byteswritten = 0, bytesneeded = 0; int error; + uint8_t irql; sc = arg; NDIS_LOCK(sc); @@ -1045,13 +1077,16 @@ ndis_set_info(arg, oid, buf, buflen) if (adapter == NULL || setfunc == NULL) return(ENXIO); + irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL); rval = setfunc(adapter, oid, buf, *buflen, &byteswritten, &bytesneeded); + FASTCALL1(hal_lower_irql, irql); if (rval == NDIS_STATUS_PENDING) { PROC_LOCK(curthread->td_proc); error = msleep(&sc->ndis_block.nmb_wkupdpctimer, - &curthread->td_proc->p_mtx, PPAUSE|PDROP, + &curthread->td_proc->p_mtx, + curthread->td_priority|PDROP, "ndisset", 5 * hz); rval = sc->ndis_block.nmb_setstat; } @@ -1091,6 +1126,7 @@ ndis_send_packets(arg, packets, cnt) __stdcall ndis_senddone_func senddonefunc; int i; ndis_packet *p; + uint8_t irql; sc = arg; adapter = sc->ndis_block.nmb_miniportadapterctx; @@ -1098,7 +1134,9 @@ ndis_send_packets(arg, packets, cnt) return(ENXIO); sendfunc = sc->ndis_chars.nmc_sendmulti_func; senddonefunc = sc->ndis_block.nmb_senddone_func; + irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL); sendfunc(adapter, packets, cnt); + FASTCALL1(hal_lower_irql, irql); for (i = 0; i < cnt; i++) { p = packets[i]; @@ -1126,6 +1164,7 @@ ndis_send_packet(arg, packet) ndis_status status; __stdcall ndis_sendsingle_handler sendfunc; __stdcall ndis_senddone_func senddonefunc; + uint8_t irql; sc = arg; adapter = sc->ndis_block.nmb_miniportadapterctx; @@ -1134,7 +1173,9 @@ ndis_send_packet(arg, packet) sendfunc = sc->ndis_chars.nmc_sendsingle_func; senddonefunc = sc->ndis_block.nmb_senddone_func; + irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL); status = sendfunc(adapter, packet, packet->np_private.npp_flags); + FASTCALL1(hal_lower_irql, irql); if (status == NDIS_STATUS_PENDING) return(0); @@ -1210,6 +1251,7 @@ ndis_reset_nic(arg) uint8_t addressing_reset; struct ifnet *ifp; int rval; + uint8_t irql; sc = arg; ifp = &sc->arpcom.ac_if; @@ -1220,11 +1262,14 @@ ndis_reset_nic(arg) if (adapter == NULL || resetfunc == NULL) return(EIO); + irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL); rval = resetfunc(&addressing_reset, adapter); + FASTCALL1(hal_lower_irql, irql); + if (rval == NDIS_STATUS_PENDING) { PROC_LOCK(curthread->td_proc); msleep(sc, &curthread->td_proc->p_mtx, - PPAUSE|PDROP, "ndisrst", 0); + curthread->td_priority|PDROP, "ndisrst", 0); } return(0); @@ -1346,10 +1391,8 @@ ndis_enable_intr(arg) __stdcall ndis_enable_interrupts_handler intrenbfunc; sc = arg; - NDIS_LOCK(sc); adapter = sc->ndis_block.nmb_miniportadapterctx; intrenbfunc = sc->ndis_chars.nmc_enable_interrupts_func; - NDIS_UNLOCK(sc); if (adapter == NULL || intrenbfunc == NULL) return; intrenbfunc(adapter); @@ -1392,10 +1435,8 @@ ndis_isr(arg, ourintr, callhandler) return(EINVAL); sc = arg; - NDIS_LOCK(sc); adapter = sc->ndis_block.nmb_miniportadapterctx; isrfunc = sc->ndis_chars.nmc_isr_func; - NDIS_UNLOCK(sc); if (adapter == NULL || isrfunc == NULL) return(ENXIO); @@ -1443,6 +1484,7 @@ ndis_get_info(arg, oid, buf, buflen) __stdcall ndis_queryinfo_handler queryfunc; uint32_t byteswritten = 0, bytesneeded = 0; int error; + uint8_t irql; sc = arg; NDIS_LOCK(sc); @@ -1453,15 +1495,18 @@ ndis_get_info(arg, oid, buf, buflen) if (adapter == NULL || queryfunc == NULL) return(ENXIO); + irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL); rval = queryfunc(adapter, oid, buf, *buflen, &byteswritten, &bytesneeded); + FASTCALL1(hal_lower_irql, irql); /* Wait for requests that block. */ if (rval == NDIS_STATUS_PENDING) { PROC_LOCK(curthread->td_proc); error = msleep(&sc->ndis_block.nmb_wkupdpctimer, - &curthread->td_proc->p_mtx, PPAUSE|PDROP, + &curthread->td_proc->p_mtx, + curthread->td_priority|PDROP, "ndisget", 5 * hz); rval = sc->ndis_block.nmb_getstat; } diff --git a/sys/compat/ndis/ndis_var.h b/sys/compat/ndis/ndis_var.h index cd4d82b..f2c3566 100644 --- a/sys/compat/ndis/ndis_var.h +++ b/sys/compat/ndis/ndis_var.h @@ -1152,6 +1152,9 @@ typedef struct ndis_packet ndis_packet; /* mbuf ext type for NDIS */ #define EXT_NDIS 0x999 +/* mtx type for NDIS */ +#define MTX_NDIS_LOCK "NDIS lock" + struct ndis_filterdbs { union { void *nf_ethdb; @@ -1513,6 +1516,8 @@ extern int ndis_add_sysctl(void *, char *, char *, char *, int); extern int ndis_flush_sysctls(void *); extern int ndis_sched(void (*)(void *), void *, int); extern int ndis_unsched(void (*)(void *), void *, int); +extern int ndis_thsuspend(struct proc *, int); +extern void ndis_thresume(struct proc *); __END_DECLS #endif /* _NDIS_VAR_H_ */ diff --git a/sys/compat/ndis/ntoskrnl_var.h b/sys/compat/ndis/ntoskrnl_var.h index a6d2d80..1e7b5a1 100644 --- a/sys/compat/ndis/ntoskrnl_var.h +++ b/sys/compat/ndis/ntoskrnl_var.h @@ -189,6 +189,7 @@ typedef struct nt_dispatch_header nt_dispatch_header; #define LOW_LEVEL 0 #define APC_LEVEL 1 #define DISPATCH_LEVEL 2 +#define DEVICE_LEVEL (DISPATCH_LEVEL + 1) #define PROFILE_LEVEL 27 #define CLOCK1_LEVEL 28 #define CLOCK2_LEVEL 28 @@ -199,6 +200,18 @@ typedef struct nt_dispatch_header nt_dispatch_header; #define SYNC_LEVEL_UP DISPATCH_LEVEL #define SYNC_LEVEL_MP (IPI_LEVEL - 1) +#define AT_PASSIVE_LEVEL(td) \ + ((td)->td_proc->p_flag & P_KTHREAD == FALSE) + +#define AT_DISPATCH_LEVEL(td) \ + ((td)->td_priority == PI_SOFT) + +#define AT_DIRQL_LEVEL(td) \ + ((td)->td_priority < PRI_MIN_KERN) + +#define AT_HIGH_LEVEL(td) \ + ((td)->td_critnest != 0) + struct nt_objref { nt_dispatch_header no_dh; void *no_obj; @@ -474,7 +487,6 @@ typedef uint32_t (*driver_dispatch)(device_object *, irp *); #define NDIS_KSTACK_PAGES 8 extern image_patch_table ntoskrnl_functbl[]; -extern struct mtx *ntoskrnl_dispatchlock; __BEGIN_DECLS extern int ntoskrnl_libinit(void); @@ -489,13 +501,26 @@ __stdcall extern uint8_t ntoskrnl_set_timer_ex(ktimer *, int64_t, uint32_t, kdpc *); __stdcall extern uint8_t ntoskrnl_cancel_timer(ktimer *); __stdcall extern uint8_t ntoskrnl_read_timer(ktimer *); -__stdcall uint32_t ntoskrnl_waitforobj(nt_dispatch_header *, uint32_t, +__stdcall extern uint32_t ntoskrnl_waitforobj(nt_dispatch_header *, uint32_t, uint32_t, uint8_t, int64_t *); -__stdcall void ntoskrnl_init_event(nt_kevent *, uint32_t, uint8_t); -__stdcall void ntoskrnl_clear_event(nt_kevent *); -__stdcall uint32_t ntoskrnl_read_event(nt_kevent *); -__stdcall uint32_t ntoskrnl_set_event(nt_kevent *, uint32_t, uint8_t); -__stdcall uint32_t ntoskrnl_reset_event(nt_kevent *); +__stdcall extern void ntoskrnl_init_event(nt_kevent *, uint32_t, uint8_t); +__stdcall extern void ntoskrnl_clear_event(nt_kevent *); +__stdcall extern uint32_t ntoskrnl_read_event(nt_kevent *); +__stdcall extern uint32_t ntoskrnl_set_event(nt_kevent *, uint32_t, uint8_t); +__stdcall extern uint32_t ntoskrnl_reset_event(nt_kevent *); +__stdcall extern void ntoskrnl_lock_dpc(/*kspin_lock * */ void); +__stdcall extern void ntoskrnl_unlock_dpc(/*kspin_lock * */ void); + +/* + * On the Windows x86 arch, KeAcquireSpinLock() and KeReleaseSpinLock() + * routines live in the HAL. We try to imitate this behavior. + */ +#ifdef __i386__ +#define ntoskrnl_acquire_spinlock(a, b) \ + *(b) = FASTCALL(hal_lock, a, 0) +#define ntoskrnl_release_spinlock(a, b) \ + FASTCALL(hal_unlock, a, b) +#endif /* __i386__ */ __END_DECLS #endif /* _NTOSKRNL_VAR_H_ */ diff --git a/sys/compat/ndis/pe_var.h b/sys/compat/ndis/pe_var.h index d267a8c..e156f0f 100644 --- a/sys/compat/ndis/pe_var.h +++ b/sys/compat/ndis/pe_var.h @@ -422,6 +422,51 @@ typedef struct image_patch_table image_patch_table; #define __stdcall __attribute__((__stdcall__)) #endif + +/* + * This mess allows us to call a _fastcall style routine with our + * version of gcc, which lacks __attribute__((__fastcall__)). Only + * has meaning on x86; everywhere else, it's a no-op. + */ + +#ifdef __i386__ +typedef __stdcall int (*fcall)(void); +typedef __stdcall int (*fcall2)(int); +static __inline uint32_t +fastcall1(fcall f, uint32_t a) +{ + __asm__ __volatile__ ("movl %0,%%ecx" : : "r" (a)); + return(f()); +} + +static __inline uint32_t +fastcall2(fcall f, uint32_t a, uint32_t b) +{ + __asm__ __volatile__ ("movl %0,%%ecx" : : "r" (a)); + __asm__ __volatile__ ("movl %0,%%edx" : : "r" (b)); + return(f()); +} + +static __inline uint32_t +fastcall3(fcall2 f, uint32_t a, uint32_t b, uint32_t c) +{ + __asm__ __volatile__ ("movl %0,%%ecx" : : "r" (a)); + __asm__ __volatile__ ("movl %0,%%edx" : : "r" (b)); + return(f(c)); +} + +#define FASTCALL1(f, a) \ + fastcall1((fcall)(f), (uint32_t)(a)) +#define FASTCALL2(f, a, b) \ + fastcall2((fcall)(f), (uint32_t)(a), (uint32_t)(b)) +#define FASTCALL3(f, a, b, c) \ + fastcall3((fcall2)(f), (uint32_t)(a), (uint32_t)(b), (uint32_t)(c)) +#else +#define FASTCALL1(f, a) (f)((a)) +#define FASTCALL2(f, a, b) (f)((a), (b)) +#define FASTCALL3(f, a, b, c) (f)((a), (b), (c)) +#endif /* __i386__ */ + __BEGIN_DECLS extern int pe_get_dos_header(vm_offset_t, image_dos_header *); extern int pe_is_nt_image(vm_offset_t); diff --git a/sys/compat/ndis/subr_hal.c b/sys/compat/ndis/subr_hal.c index 972508f..beae7c1 100644 --- a/sys/compat/ndis/subr_hal.c +++ b/sys/compat/ndis/subr_hal.c @@ -41,6 +41,8 @@ __FBSDID("$FreeBSD$"); #include <sys/kernel.h> #include <sys/lock.h> #include <sys/mutex.h> +#include <sys/proc.h> +#include <sys/sched.h> #include <sys/systm.h> #include <machine/clock.h> @@ -76,12 +78,7 @@ __stdcall static void hal_readport_buf_ushort(uint16_t *, uint16_t *, uint32_t); __stdcall static void hal_readport_buf_uchar(uint8_t *, uint8_t *, uint32_t); -__stdcall static uint8_t hal_lock(/*kspin_lock * */void); -__stdcall static void hal_unlock(/*kspin_lock *, uint8_t*/void); -__stdcall static uint8_t hal_irql(void); __stdcall static uint64_t hal_perfcount(uint64_t *); -__stdcall static uint8_t hal_raise_irql(/*uint8_t*/ void); -__stdcall static void hal_lower_irql(/*uint8_t*/ void); __stdcall static void dummy (void); extern struct mtx_pool *ndis_mtxpool; @@ -208,33 +205,94 @@ hal_readport_buf_uchar(port, val, cnt) return; } -__stdcall static uint8_t +/* + * The spinlock implementation in Windows differs from that of FreeBSD. + * The basic operation of spinlocks involves two steps: 1) spin in a + * tight loop while trying to acquire a lock, 2) after obtaining the + * lock, disable preemption. (Note that on uniprocessor systems, you're + * allowed to skip the first step and just lock out pre-emption, since + * it's not possible for you to be in contention with another running + * thread.) Later, you release the lock then re-enable preemption. + * The difference between Windows and FreeBSD lies in how preemption + * is disabled. In FreeBSD, it's done using critical_enter(), which on + * the x86 arch translates to a cli instruction. This masks off all + * interrupts, and effectively stops the scheduler from ever running + * so _nothing_ can execute except the current thread. In Windows, + * preemption is disabled by raising the processor IRQL to DISPATCH_LEVEL. + * This stops other threads from running, but does _not_ block device + * interrupts. This means ISRs can still run, and they can make other + * threads runable, but those other threads won't be able to execute + * until the current thread lowers the IRQL to something less than + * DISPATCH_LEVEL. + * + * In FreeBSD, ISRs run in interrupt threads, so to duplicate the + * Windows notion of IRQLs, we use the following rules: + * + * PASSIVE_LEVEL == normal kernel thread priority + * DISPATCH_LEVEL == lowest interrupt thread priotity (PI_SOFT) + * DEVICE_LEVEL == highest interrupt thread priority (PI_REALTIME) + * HIGH_LEVEL == interrupts disabled (critical_enter()) + * + * Be aware that, at least on the x86 arch, the Windows spinlock + * functions are divided up in peculiar ways. The actual spinlock + * functions are KfAcquireSpinLock() and KfReleaseSpinLock(), and + * they live in HAL.dll. Meanwhile, KeInitializeSpinLock(), + * KefAcquireSpinLockAtDpcLevel() and KefReleaseSpinLockFromDpcLevel() + * live in ntoskrnl.exe. Most Windows source code will call + * KeAcquireSpinLock() and KeReleaseSpinLock(), but these are just + * macros that call KfAcquireSpinLock() and KfReleaseSpinLock(). + * KefAcquireSpinLockAtDpcLevel() and KefReleaseSpinLockFromDpcLevel() + * perform the lock aquisition/release functions without doing the + * IRQL manipulation, and are used when one is already running at + * DISPATCH_LEVEL. Make sense? Good. + * + * According to the Microsoft documentation, any thread that calls + * KeAcquireSpinLock() must be running at IRQL <= DISPATCH_LEVEL. If + * we detect someone trying to acquire a spinlock from DEVICE_LEVEL + * or HIGH_LEVEL, we panic. + */ + +__stdcall uint8_t hal_lock(/*lock*/void) { kspin_lock *lock; + uint8_t oldirql; __asm__ __volatile__ ("" : "=c" (lock)); - mtx_pool_lock(ndis_mtxpool, (struct mtx *)*lock); - return(0); + /* I am so going to hell for this. */ + if (hal_irql() > DISPATCH_LEVEL) + panic("IRQL_NOT_LESS_THAN_OR_EQUAL"); + + oldirql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL); + FASTCALL1(ntoskrnl_lock_dpc, lock); + return(oldirql); } -__stdcall static void +__stdcall void hal_unlock(/*lock, newirql*/void) { kspin_lock *lock; - uint8_t newiqrl; + uint8_t newirql; + + __asm__ __volatile__ ("" : "=c" (lock), "=d" (newirql)); - __asm__ __volatile__ ("" : "=c" (lock), "=d" (newiqrl)); + FASTCALL1(ntoskrnl_unlock_dpc, lock); + FASTCALL1(hal_lower_irql, newirql); - mtx_pool_unlock(ndis_mtxpool, (struct mtx *)*lock); return; } -__stdcall static uint8_t +__stdcall uint8_t hal_irql(void) { - return(DISPATCH_LEVEL); + if (AT_DISPATCH_LEVEL(curthread)) + return(DISPATCH_LEVEL); + if (AT_DIRQL_LEVEL(curthread)) + return(DEVICE_LEVEL); + if (AT_HIGH_LEVEL(curthread)) + return(HIGH_LEVEL); + return(PASSIVE_LEVEL); } __stdcall static uint64_t @@ -247,22 +305,63 @@ hal_perfcount(freq) return((uint64_t)ticks); } -__stdcall static uint8_t +__stdcall uint8_t hal_raise_irql(/*irql*/ void) { uint8_t irql; + uint8_t oldirql; __asm__ __volatile__ ("" : "=c" (irql)); - return(0); + switch(irql) { + case HIGH_LEVEL: + oldirql = hal_irql(); + critical_enter(); + break; + case DEVICE_LEVEL: + mtx_lock_spin(&sched_lock); + oldirql = curthread->td_priority; + sched_prio(curthread, PI_REALTIME); + mtx_unlock_spin(&sched_lock); + break; + case DISPATCH_LEVEL: + mtx_lock_spin(&sched_lock); + oldirql = curthread->td_priority; + sched_prio(curthread, PI_SOFT); + mtx_unlock_spin(&sched_lock); + break; + default: + panic("can't raise IRQL to unknown level %d", irql); + break; + } + + return(oldirql); } -__stdcall static void -hal_lower_irql(/*irql*/ void) +__stdcall void +hal_lower_irql(/*oldirql*/ void) { + uint8_t oldirql; uint8_t irql; - __asm__ __volatile__ ("" : "=c" (irql)); + __asm__ __volatile__ ("" : "=c" (oldirql)); + + irql = hal_irql(); + + switch (irql) { + case HIGH_LEVEL: + critical_exit(); + break; + case DEVICE_LEVEL: + case DISPATCH_LEVEL: + mtx_lock_spin(&sched_lock); + sched_prio(curthread, oldirql); + mtx_unlock_spin(&sched_lock); + break; + default: + panic("can't lower IRQL to unknown level %d", irql); + break; + } return; } diff --git a/sys/compat/ndis/subr_ndis.c b/sys/compat/ndis/subr_ndis.c index 38bc6b8..24320b0 100644 --- a/sys/compat/ndis/subr_ndis.c +++ b/sys/compat/ndis/subr_ndis.c @@ -97,15 +97,14 @@ __FBSDID("$FreeBSD$"); #include <compat/ndis/pe_var.h> #include <compat/ndis/resource_var.h> #include <compat/ndis/ntoskrnl_var.h> +#include <compat/ndis/hal_var.h> #include <compat/ndis/ndis_var.h> #include <compat/ndis/cfg_var.h> #include <dev/if_ndis/if_ndisvar.h> #define FUNC void(*)(void) -static struct mtx *ndis_interlock; static char ndis_filepath[MAXPATHLEN]; -struct mtx_pool *ndis_mtxpool; extern struct nd_head ndis_devhead; SYSCTL_STRING(_hw, OID_AUTO, ndis_filepath, CTLFLAG_RW, ndis_filepath, @@ -139,6 +138,8 @@ __stdcall static void ndis_create_lock(ndis_spin_lock *); __stdcall static void ndis_destroy_lock(ndis_spin_lock *); __stdcall static void ndis_lock(ndis_spin_lock *); __stdcall static void ndis_unlock(ndis_spin_lock *); +__stdcall static void ndis_lock_dpr(ndis_spin_lock *); +__stdcall static void ndis_unlock_dpr(ndis_spin_lock *); __stdcall static uint32_t ndis_read_pci(ndis_handle, uint32_t, uint32_t, void *, uint32_t); __stdcall static uint32_t ndis_write_pci(ndis_handle, uint32_t, @@ -296,16 +297,12 @@ int ndis_libinit() { strcpy(ndis_filepath, "/compat/ndis"); - ndis_mtxpool = mtx_pool_create("ndis mutex pool", - 1024, MTX_DEF | MTX_RECURSE | MTX_DUPOK);; - ndis_interlock = mtx_pool_alloc(ndis_mtxpool); return(0); } int ndis_libfini() { - mtx_pool_destroy(&ndis_mtxpool); return(0); } @@ -712,35 +709,82 @@ ndis_close_cfg(cfg) return; } +/* + * Initialize a Windows spinlock. + */ __stdcall static void ndis_create_lock(lock) ndis_spin_lock *lock; { - lock->nsl_spinlock = (ndis_kspin_lock)mtx_pool_alloc(ndis_mtxpool); + lock->nsl_spinlock = 0; + lock->nsl_kirql = 0; + return; } +/* + * Destroy a Windows spinlock. This is a no-op for now. There are two reasons + * for this. One is that it's sort of superfluous: we don't have to do anything + * special to deallocate the spinlock. The other is that there are some buggy + * drivers which call NdisFreeSpinLock() _after_ calling NdisFreeMemory() on + * the block of memory in which the spinlock resides. (Yes, ADMtek, I'm + * talking to you.) + */ __stdcall static void ndis_destroy_lock(lock) ndis_spin_lock *lock; { - /* We use a mutex pool, so this is a no-op. */ +#ifdef notdef + lock->nsl_spinlock = 0; + lock->nsl_kirql = 0; +#endif return; } +/* + * Acquire a spinlock from IRQL <= DISPATCH_LEVEL. + */ + __stdcall static void ndis_lock(lock) ndis_spin_lock *lock; { - mtx_pool_lock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); + lock->nsl_kirql = FASTCALL2(hal_lock, + &lock->nsl_spinlock, DISPATCH_LEVEL); return; } +/* + * Release a spinlock from IRQL == DISPATCH_LEVEL. + */ + __stdcall static void ndis_unlock(lock) ndis_spin_lock *lock; { - mtx_pool_unlock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); + FASTCALL2(hal_unlock, &lock->nsl_spinlock, lock->nsl_kirql); + return; +} + +/* + * Acquire a spinlock when already running at IRQL == DISPATCH_LEVEL. + */ +__stdcall static void +ndis_lock_dpr(lock) + ndis_spin_lock *lock; +{ + FASTCALL1(ntoskrnl_lock_dpc, &lock->nsl_spinlock); + return; +} + +/* + * Release a spinlock without leaving IRQL == DISPATCH_LEVEL. + */ +__stdcall static void +ndis_unlock_dpr(lock) + ndis_spin_lock *lock; +{ + FASTCALL1(ntoskrnl_unlock_dpc, &lock->nsl_spinlock); return; } @@ -2196,13 +2240,14 @@ ndis_insert_head(head, entry, lock) { list_entry *flink; - mtx_pool_lock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); + lock->nsl_kirql = FASTCALL2(hal_lock, + &lock->nsl_spinlock, DISPATCH_LEVEL); flink = head->nle_flink; entry->nle_flink = flink; entry->nle_blink = head; flink->nle_blink = entry; head->nle_flink = entry; - mtx_pool_unlock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); + FASTCALL2(hal_unlock, &lock->nsl_spinlock, lock->nsl_kirql); return(flink); } @@ -2215,12 +2260,13 @@ ndis_remove_head(head, lock) list_entry *flink; list_entry *entry; - mtx_pool_lock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); + lock->nsl_kirql = FASTCALL2(hal_lock, + &lock->nsl_spinlock, DISPATCH_LEVEL); entry = head->nle_flink; flink = entry->nle_flink; head->nle_flink = flink; flink->nle_blink = head; - mtx_pool_unlock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); + FASTCALL2(hal_unlock, &lock->nsl_spinlock, lock->nsl_kirql); return(entry); } @@ -2233,13 +2279,14 @@ ndis_insert_tail(head, entry, lock) { list_entry *blink; - mtx_pool_lock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); + lock->nsl_kirql = FASTCALL2(hal_lock, + &lock->nsl_spinlock, DISPATCH_LEVEL); blink = head->nle_blink; entry->nle_flink = head; entry->nle_blink = blink; blink->nle_flink = entry; head->nle_blink = entry; - mtx_pool_unlock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); + FASTCALL2(hal_unlock, &lock->nsl_spinlock, lock->nsl_kirql); return(blink); } @@ -2259,9 +2306,9 @@ ndis_sync_with_intr(intr, syncfunc, syncctx) sc = (struct ndis_softc *)intr->ni_block->nmb_ifp; sync = syncfunc; - mtx_pool_lock(ndis_mtxpool, sc->ndis_intrmtx); + mtx_lock(&sc->ndis_intrmtx); rval = sync(syncctx); - mtx_pool_unlock(ndis_mtxpool, sc->ndis_intrmtx); + mtx_unlock(&sc->ndis_intrmtx); return(rval); } @@ -2853,10 +2900,10 @@ image_patch_table ndis_functbl[] = { { "NdisCloseConfiguration", (FUNC)ndis_close_cfg }, { "NdisReadConfiguration", (FUNC)ndis_read_cfg }, { "NdisOpenConfiguration", (FUNC)ndis_open_cfg }, - { "NdisReleaseSpinLock", (FUNC)ndis_unlock }, - { "NdisDprAcquireSpinLock", (FUNC)ndis_lock }, - { "NdisDprReleaseSpinLock", (FUNC)ndis_unlock }, { "NdisAcquireSpinLock", (FUNC)ndis_lock }, + { "NdisReleaseSpinLock", (FUNC)ndis_unlock }, + { "NdisDprAcquireSpinLock", (FUNC)ndis_lock_dpr }, + { "NdisDprReleaseSpinLock", (FUNC)ndis_unlock_dpr }, { "NdisAllocateSpinLock", (FUNC)ndis_create_lock }, { "NdisFreeSpinLock", (FUNC)ndis_destroy_lock }, { "NdisFreeMemory", (FUNC)ndis_free }, diff --git a/sys/compat/ndis/subr_ntoskrnl.c b/sys/compat/ndis/subr_ntoskrnl.c index 8c9646c..7162d59 100644 --- a/sys/compat/ndis/subr_ntoskrnl.c +++ b/sys/compat/ndis/subr_ntoskrnl.c @@ -121,8 +121,6 @@ __stdcall static slist_entry *ntoskrnl_push_slist_ex(/*slist_header *, slist_entry *,*/ kspin_lock *); __stdcall static slist_entry *ntoskrnl_pop_slist_ex(/*slist_header *, kspin_lock * */void); -__stdcall static void ntoskrnl_lock_dpc(/*kspin_lock * */ void); -__stdcall static void ntoskrnl_unlock_dpc(/*kspin_lock * */ void); __stdcall static uint32_t ntoskrnl_interlock_inc(/*volatile uint32_t * */ void); __stdcall static uint32_t @@ -167,17 +165,17 @@ static uint32_t ntoskrnl_dbgprint(char *, ...); __stdcall static void ntoskrnl_debugger(void); __stdcall static void dummy(void); -static struct mtx *ntoskrnl_interlock; -struct mtx *ntoskrnl_dispatchlock; -extern struct mtx_pool *ndis_mtxpool; +static struct mtx ntoskrnl_dispatchlock; +static kspin_lock ntoskrnl_global; static int ntoskrnl_kth = 0; static struct nt_objref_head ntoskrnl_reflist; int ntoskrnl_libinit() { - ntoskrnl_interlock = mtx_pool_alloc(ndis_mtxpool); - ntoskrnl_dispatchlock = mtx_pool_alloc(ndis_mtxpool); + mtx_init(&ntoskrnl_dispatchlock, + "ntoskrnl dispatch lock", MTX_NDIS_LOCK, MTX_DEF); + ntoskrnl_init_lock(&ntoskrnl_global); TAILQ_INIT(&ntoskrnl_reflist); return(0); } @@ -185,6 +183,7 @@ ntoskrnl_libinit() int ntoskrnl_libfini() { + mtx_destroy(&ntoskrnl_dispatchlock); return(0); } @@ -324,16 +323,13 @@ ntoskrnl_wakeup(arg) obj = arg; - mtx_pool_lock(ndis_mtxpool, ntoskrnl_dispatchlock); + mtx_lock(&ntoskrnl_dispatchlock); obj->dh_sigstate = TRUE; e = obj->dh_waitlisthead.nle_flink; while (e != &obj->dh_waitlisthead) { w = (wait_block *)e; td = w->wb_kthread; - if (td->td_proc->p_flag & P_KTHREAD) - kthread_resume(td->td_proc); - else - wakeup(td); + ndis_thresume(td->td_proc); /* * For synchronization objects, only wake up * the first waiter. @@ -342,7 +338,7 @@ ntoskrnl_wakeup(arg) break; e = e->nle_flink; } - mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock); + mtx_unlock(&ntoskrnl_dispatchlock); return; } @@ -436,7 +432,7 @@ ntoskrnl_waitforobj(obj, reason, mode, alertable, duetime) if (obj == NULL) return(STATUS_INVALID_PARAMETER); - mtx_pool_lock(ndis_mtxpool, ntoskrnl_dispatchlock); + mtx_lock(&ntoskrnl_dispatchlock); /* * See if the object is a mutex. If so, and we already own @@ -455,13 +451,13 @@ ntoskrnl_waitforobj(obj, reason, mode, alertable, duetime) obj->dh_sigstate = FALSE; km->km_acquirecnt++; km->km_ownerthread = curthread->td_proc; - mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock); + mtx_unlock(&ntoskrnl_dispatchlock); return (STATUS_SUCCESS); } } else if (obj->dh_sigstate == TRUE) { if (obj->dh_type == EVENT_TYPE_SYNC) obj->dh_sigstate = FALSE; - mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock); + mtx_unlock(&ntoskrnl_dispatchlock); return (STATUS_SUCCESS); } @@ -496,22 +492,18 @@ ntoskrnl_waitforobj(obj, reason, mode, alertable, duetime) } } - mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock); + mtx_unlock(&ntoskrnl_dispatchlock); - if (td->td_proc->p_flag & P_KTHREAD) - error = kthread_suspend(td->td_proc, - duetime == NULL ? 0 : tvtohz(&tv)); - else - error = tsleep(td, PPAUSE|PDROP, "ndisws", - duetime == NULL ? 0 : tvtohz(&tv)); + error = ndis_thsuspend(td->td_proc, + duetime == NULL ? 0 : tvtohz(&tv)); - mtx_pool_lock(ndis_mtxpool, ntoskrnl_dispatchlock); + mtx_lock(&ntoskrnl_dispatchlock); /* We timed out. Leave the object alone and return status. */ if (error == EWOULDBLOCK) { REMOVE_LIST_ENTRY((&w.wb_waitlist)); - mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock); + mtx_unlock(&ntoskrnl_dispatchlock); return(STATUS_TIMEOUT); } @@ -534,7 +526,7 @@ ntoskrnl_waitforobj(obj, reason, mode, alertable, duetime) obj->dh_sigstate = FALSE; REMOVE_LIST_ENTRY((&w.wb_waitlist)); - mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock); + mtx_unlock(&ntoskrnl_dispatchlock); return(STATUS_SUCCESS); } @@ -565,7 +557,7 @@ ntoskrnl_waitforobjs(cnt, obj, wtype, reason, mode, if (cnt > THREAD_WAIT_OBJECTS && wb_array == NULL) return(STATUS_INVALID_PARAMETER); - mtx_pool_lock(ndis_mtxpool, ntoskrnl_dispatchlock); + mtx_lock(&ntoskrnl_dispatchlock); if (wb_array == NULL) w = &_wb_array[0]; @@ -583,8 +575,7 @@ ntoskrnl_waitforobjs(cnt, obj, wtype, reason, mode, km->km_acquirecnt++; km->km_ownerthread = curthread->td_proc; if (wtype == WAITTYPE_ANY) { - mtx_pool_unlock(ndis_mtxpool, - ntoskrnl_dispatchlock); + mtx_unlock(&ntoskrnl_dispatchlock); return (STATUS_WAIT_0 + i); } } @@ -592,8 +583,7 @@ ntoskrnl_waitforobjs(cnt, obj, wtype, reason, mode, if (obj[i]->dh_type == EVENT_TYPE_SYNC) obj[i]->dh_sigstate = FALSE; if (wtype == WAITTYPE_ANY) { - mtx_pool_unlock(ndis_mtxpool, - ntoskrnl_dispatchlock); + mtx_unlock(&ntoskrnl_dispatchlock); return (STATUS_WAIT_0 + i); } } @@ -633,16 +623,12 @@ ntoskrnl_waitforobjs(cnt, obj, wtype, reason, mode, while (wcnt) { nanotime(&t1); - mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock); + mtx_unlock(&ntoskrnl_dispatchlock); - if (td->td_proc->p_flag & P_KTHREAD) - error = kthread_suspend(td->td_proc, - duetime == NULL ? 0 : tvtohz(&tv)); - else - error = tsleep(td, PPAUSE|PDROP, "ndisws", - duetime == NULL ? 0 : tvtohz(&tv)); + error = ndis_thsuspend(td->td_proc, + duetime == NULL ? 0 : tvtohz(&tv)); - mtx_pool_lock(ndis_mtxpool, ntoskrnl_dispatchlock); + mtx_lock(&ntoskrnl_dispatchlock); nanotime(&t2); for (i = 0; i < cnt; i++) { @@ -678,16 +664,16 @@ ntoskrnl_waitforobjs(cnt, obj, wtype, reason, mode, } if (error == EWOULDBLOCK) { - mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock); + mtx_unlock(&ntoskrnl_dispatchlock); return(STATUS_TIMEOUT); } if (wtype == WAITTYPE_ANY && wcnt) { - mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock); + mtx_unlock(&ntoskrnl_dispatchlock); return(STATUS_WAIT_0 + widx); } - mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock); + mtx_unlock(&ntoskrnl_dispatchlock); return(STATUS_SUCCESS); } @@ -880,9 +866,12 @@ ntoskrnl_init_lookaside(lookaside, allocfunc, freefunc, uint32_t tag; uint16_t depth; { - struct mtx *mtx; + bzero((char *)lookaside, sizeof(paged_lookaside_list)); - lookaside->nll_l.gl_size = size; + if (size < sizeof(slist_entry)) + lookaside->nll_l.gl_size = sizeof(slist_entry); + else + lookaside->nll_l.gl_size = size; lookaside->nll_l.gl_tag = tag; if (allocfunc == NULL) lookaside->nll_l.gl_allocfunc = ntoskrnl_allocfunc; @@ -894,8 +883,7 @@ ntoskrnl_init_lookaside(lookaside, allocfunc, freefunc, else lookaside->nll_l.gl_freefunc = freefunc; - mtx = mtx_pool_alloc(ndis_mtxpool); - lookaside->nll_obsoletelock = (kspin_lock)mtx; + ntoskrnl_init_lock(&lookaside->nll_obsoletelock); lookaside->nll_l.gl_depth = LOOKASIDE_DEPTH; lookaside->nll_l.gl_maxdepth = LOOKASIDE_DEPTH; @@ -928,8 +916,6 @@ ntoskrnl_init_nplookaside(lookaside, allocfunc, freefunc, uint32_t tag; uint16_t depth; { - struct mtx *mtx; - bzero((char *)lookaside, sizeof(npaged_lookaside_list)); if (size < sizeof(slist_entry)) @@ -947,8 +933,7 @@ ntoskrnl_init_nplookaside(lookaside, allocfunc, freefunc, else lookaside->nll_l.gl_freefunc = freefunc; - mtx = mtx_pool_alloc(ndis_mtxpool); - lookaside->nll_obsoletelock = (kspin_lock)mtx; + ntoskrnl_init_lock(&lookaside->nll_obsoletelock); lookaside->nll_l.gl_depth = LOOKASIDE_DEPTH; lookaside->nll_l.gl_maxdepth = LOOKASIDE_DEPTH; @@ -987,9 +972,8 @@ ntoskrnl_push_slist(/*head, entry*/ void) __asm__ __volatile__ ("" : "=c" (head), "=d" (entry)); - mtx_pool_lock(ndis_mtxpool, ntoskrnl_interlock); - oldhead = ntoskrnl_pushsl(head, entry); - mtx_pool_unlock(ndis_mtxpool, ntoskrnl_interlock); + oldhead = (slist_entry *)FASTCALL3(ntoskrnl_push_slist_ex, + head, entry, &ntoskrnl_global); return(oldhead); } @@ -1002,9 +986,8 @@ ntoskrnl_pop_slist(/*head*/ void) __asm__ __volatile__ ("" : "=c" (head)); - mtx_pool_lock(ndis_mtxpool, ntoskrnl_interlock); - first = ntoskrnl_popsl(head); - mtx_pool_unlock(ndis_mtxpool, ntoskrnl_interlock); + first = (slist_entry *)FASTCALL2(ntoskrnl_pop_slist_ex, + head, &ntoskrnl_global); return(first); } @@ -1016,12 +999,13 @@ ntoskrnl_push_slist_ex(/*head, entry,*/ lock) slist_header *head; slist_entry *entry; slist_entry *oldhead; + uint8_t irql; __asm__ __volatile__ ("" : "=c" (head), "=d" (entry)); - mtx_pool_lock(ndis_mtxpool, (struct mtx *)*lock); + irql = FASTCALL2(hal_lock, lock, DISPATCH_LEVEL); oldhead = ntoskrnl_pushsl(head, entry); - mtx_pool_unlock(ndis_mtxpool, (struct mtx *)*lock); + FASTCALL2(hal_unlock, lock, irql); return(oldhead); } @@ -1032,36 +1016,38 @@ ntoskrnl_pop_slist_ex(/*head, lock*/ void) slist_header *head; kspin_lock *lock; slist_entry *first; + uint8_t irql; __asm__ __volatile__ ("" : "=c" (head), "=d" (lock)); - mtx_pool_lock(ndis_mtxpool, (struct mtx *)*lock); + irql = FASTCALL2(hal_lock, lock, DISPATCH_LEVEL); first = ntoskrnl_popsl(head); - mtx_pool_unlock(ndis_mtxpool, (struct mtx *)*lock); + FASTCALL2(hal_unlock, lock, irql); return(first); } -__stdcall static void +__stdcall void ntoskrnl_lock_dpc(/*lock*/ void) { kspin_lock *lock; __asm__ __volatile__ ("" : "=c" (lock)); - mtx_pool_lock(ndis_mtxpool, (struct mtx *)*lock); + while (atomic_cmpset_int((volatile u_int *)lock, 0, 1) == 0) + /* do noting */; return; } -__stdcall static void +__stdcall void ntoskrnl_unlock_dpc(/*lock*/ void) { kspin_lock *lock; __asm__ __volatile__ ("" : "=c" (lock)); - mtx_pool_unlock(ndis_mtxpool, (struct mtx *)*lock); + atomic_cmpset_int((volatile u_int *)lock, 1, 0); return; } @@ -1093,12 +1079,13 @@ ntoskrnl_interlock_addstat(/*addend, inc*/) { uint64_t *addend; uint32_t inc; + uint8_t irql; __asm__ __volatile__ ("" : "=c" (addend), "=d" (inc)); - mtx_pool_lock(ndis_mtxpool, ntoskrnl_interlock); + irql = FASTCALL2(hal_lock, &ntoskrnl_global, DISPATCH_LEVEL); *addend += inc; - mtx_pool_unlock(ndis_mtxpool, ntoskrnl_interlock); + FASTCALL2(hal_unlock, &ntoskrnl_global, irql); return; }; @@ -1196,7 +1183,7 @@ __stdcall static void ntoskrnl_init_lock(lock) kspin_lock *lock; { - *lock = (kspin_lock)mtx_pool_alloc(ndis_mtxpool); + *lock = 0; return; } @@ -1423,18 +1410,18 @@ ntoskrnl_release_mutex(kmutex, kwait) kmutant *kmutex; uint8_t kwait; { - mtx_pool_lock(ndis_mtxpool, ntoskrnl_dispatchlock); + mtx_lock(&ntoskrnl_dispatchlock); if (kmutex->km_ownerthread != curthread->td_proc) { - mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock); + mtx_unlock(&ntoskrnl_dispatchlock); return(STATUS_MUTANT_NOT_OWNED); } kmutex->km_acquirecnt--; if (kmutex->km_acquirecnt == 0) { kmutex->km_ownerthread = NULL; - mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock); + mtx_unlock(&ntoskrnl_dispatchlock); ntoskrnl_wakeup(&kmutex->km_header); } else - mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock); + mtx_unlock(&ntoskrnl_dispatchlock); return(kmutex->km_acquirecnt); } @@ -1465,10 +1452,10 @@ ntoskrnl_reset_event(kevent) { uint32_t prevstate; - mtx_pool_lock(ndis_mtxpool, ntoskrnl_dispatchlock); + mtx_lock(&ntoskrnl_dispatchlock); prevstate = kevent->k_header.dh_sigstate; kevent->k_header.dh_sigstate = FALSE; - mtx_pool_unlock(ndis_mtxpool, ntoskrnl_dispatchlock); + mtx_unlock(&ntoskrnl_dispatchlock); return(prevstate); } @@ -1628,7 +1615,7 @@ ntoskrnl_thread_exit(status) ntoskrnl_kth--; - kthread_exit(0); + kthread_exit(0); return(0); /* notreached */ } @@ -1721,7 +1708,8 @@ ntoskrnl_init_timer_ex(timer, type) /* * This is a wrapper for Windows deferred procedure calls that * have been placed on an NDIS thread work queue. We need it - * since the DPC could be a _stdcall function. + * since the DPC could be a _stdcall function. Also, as far as + * I can tell, defered procedure calls must run at DISPATCH_LEVEL. */ static void ntoskrnl_run_dpc(arg) @@ -1729,10 +1717,13 @@ ntoskrnl_run_dpc(arg) { __stdcall kdpc_func dpcfunc; kdpc *dpc; + uint8_t irql; dpc = arg; dpcfunc = (kdpc_func)dpc->k_deferedfunc; + irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL); dpcfunc(dpc, dpc->k_deferredctx, dpc->k_sysarg1, dpc->k_sysarg2); + FASTCALL1(hal_lower_irql, irql); return; } diff --git a/sys/dev/if_ndis/if_ndis.c b/sys/dev/if_ndis/if_ndis.c index 901b313..f7467d9 100644 --- a/sys/dev/if_ndis/if_ndis.c +++ b/sys/dev/if_ndis/if_ndis.c @@ -70,6 +70,7 @@ __FBSDID("$FreeBSD$"); #include <compat/ndis/pe_var.h> #include <compat/ndis/resource_var.h> +#include <compat/ndis/hal_var.h> #include <compat/ndis/ntoskrnl_var.h> #include <compat/ndis/ndis_var.h> #include <compat/ndis/cfg_var.h> @@ -371,8 +372,10 @@ ndis_attach(dev) sc = device_get_softc(dev); - sc->ndis_mtx = mtx_pool_alloc(ndis_mtxpool); - sc->ndis_intrmtx = mtx_pool_alloc(ndis_mtxpool); + mtx_init(&sc->ndis_mtx, "ndis softc lock", + MTX_NETWORK_LOCK, MTX_DEF); + mtx_init(&sc->ndis_intrmtx, + "ndis irq lock", MTX_NETWORK_LOCK, MTX_DEF); /* * Hook interrupt early, since calling the driver's @@ -492,7 +495,6 @@ ndis_attach(dev) /* Do media setup */ if (sc->ndis_80211) { struct ieee80211com *ic = (void *)ifp; - ndis_80211_config config; ndis_80211_rates_ex rates; struct ndis_80211_nettype_list *ntl; uint32_t arg; @@ -650,27 +652,11 @@ nonettypes: r = ndis_get_info(sc, OID_802_11_POWER_MODE, &arg, &i); if (r == 0) ic->ic_caps |= IEEE80211_C_PMGT; - i = sizeof(config); - bzero((char *)&config, sizeof(config)); - config.nc_length = i; - config.nc_fhconfig.ncf_length = sizeof(ndis_80211_config_fh); - r = ndis_get_info(sc, OID_802_11_CONFIGURATION, &config, &i); - if (r == 0) { - int chan; - chan = ieee80211_mhz2ieee(config.nc_dsconfig / 1000, 0); - if (chan < 0 || chan >= IEEE80211_CHAN_MAX) { - ic->ic_ibss_chan = &ic->ic_channels[1]; - } else - ic->ic_ibss_chan = &ic->ic_channels[chan]; - } else { - device_printf(sc->ndis_dev, "couldn't retrieve " - "channel info: %d\n", r); - ic->ic_ibss_chan = &ic->ic_channels[1]; - } bcopy(eaddr, &ic->ic_myaddr, sizeof(eaddr)); ieee80211_ifattach(ifp); ieee80211_media_init(ifp, ieee80211_media_change, ndis_media_status); + ic->ic_ibss_chan = IEEE80211_CHAN_ANYC; ic->ic_bss->ni_chan = ic->ic_ibss_chan; } else { ifmedia_init(&sc->ifmedia, IFM_IMASK, ndis_ifmedia_upd, @@ -757,6 +743,9 @@ ndis_detach(dev) sysctl_ctx_free(&sc->ndis_ctx); + mtx_destroy(&sc->ndis_mtx); + mtx_destroy(&sc->ndis_intrmtx); + return(0); } @@ -1073,8 +1062,6 @@ ndis_linksts_done(adapter) ndis_sched(ndis_starttask, ifp, NDIS_TASKQUEUE); break; case NDIS_STATUS_MEDIA_DISCONNECT: - if (sc->ndis_80211) - ndis_getstate_80211(sc); if (sc->ndis_link) ndis_sched(ndis_ticktask, sc, NDIS_TASKQUEUE); break; @@ -1091,14 +1078,17 @@ ndis_intrtask(arg) { struct ndis_softc *sc; struct ifnet *ifp; + uint8_t irql; sc = arg; ifp = &sc->arpcom.ac_if; + irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL); ndis_intrhand(sc); - mtx_pool_lock(ndis_mtxpool, sc->ndis_intrmtx); + FASTCALL1(hal_lower_irql, irql); + mtx_lock(&sc->ndis_intrmtx); ndis_enable_intr(sc); - mtx_pool_unlock(ndis_mtxpool, sc->ndis_intrmtx); + mtx_unlock(&sc->ndis_intrmtx); return; } @@ -1118,14 +1108,14 @@ ndis_intr(arg) if (sc->ndis_block.nmb_miniportadapterctx == NULL) return; - mtx_pool_lock(ndis_mtxpool, sc->ndis_intrmtx); + mtx_lock(&sc->ndis_intrmtx); if (sc->ndis_block.nmb_interrupt->ni_isrreq == TRUE) ndis_isr(sc, &is_our_intr, &call_isr); else { ndis_disable_intr(sc); call_isr = 1; } - mtx_pool_unlock(ndis_mtxpool, sc->ndis_intrmtx); + mtx_unlock(&sc->ndis_intrmtx); if ((is_our_intr || call_isr)) ndis_sched(ndis_intrtask, ifp, NDIS_SWI); @@ -1617,32 +1607,22 @@ ndis_setstate_80211(sc) device_printf (sc->ndis_dev, "set auth failed: %d\n", rval); #endif - /* Set SSID. */ - - len = sizeof(ssid); - bzero((char *)&ssid, len); - ssid.ns_ssidlen = ic->ic_des_esslen; - if (ssid.ns_ssidlen == 0) { - ssid.ns_ssidlen = 1; - } else - bcopy(ic->ic_des_essid, ssid.ns_ssid, ssid.ns_ssidlen); - rval = ndis_set_info(sc, OID_802_11_SSID, &ssid, &len); - - if (rval) - device_printf (sc->ndis_dev, "set ssid failed: %d\n", rval); - len = sizeof(config); bzero((char *)&config, len); config.nc_length = len; config.nc_fhconfig.ncf_length = sizeof(ndis_80211_config_fh); - rval = ndis_get_info(sc, OID_802_11_CONFIGURATION, &config, &len); - if (rval == 0) { - int chan; + rval = ndis_get_info(sc, OID_802_11_CONFIGURATION, &config, &len); - chan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan); + if (rval == 0 && ic->ic_ibss_chan != IEEE80211_CHAN_ANYC) { + int chan, chanflag; + + chan = ieee80211_chan2ieee(ic, ic->ic_ibss_chan); + chanflag = config.nc_dsconfig > 2500000 ? IEEE80211_CHAN_2GHZ : + IEEE80211_CHAN_5GHZ; if (chan != ieee80211_mhz2ieee(config.nc_dsconfig / 1000, 0)) { config.nc_dsconfig = - ic->ic_bss->ni_chan->ic_freq * 1000; + ic->ic_ibss_chan->ic_freq * 1000; + ic->ic_bss->ni_chan = ic->ic_ibss_chan; len = sizeof(config); config.nc_length = len; config.nc_fhconfig.ncf_length = @@ -1654,10 +1634,24 @@ ndis_setstate_80211(sc) "DS config to %ukHz: %d\n", config.nc_dsconfig, rval); } - } else + } else if (rval) device_printf(sc->ndis_dev, "couldn't retrieve " "channel info: %d\n", rval); + /* Set SSID -- always do this last. */ + + len = sizeof(ssid); + bzero((char *)&ssid, len); + ssid.ns_ssidlen = ic->ic_des_esslen; + if (ssid.ns_ssidlen == 0) { + ssid.ns_ssidlen = 1; + } else + bcopy(ic->ic_des_essid, ssid.ns_ssid, ssid.ns_ssidlen); + rval = ndis_set_info(sc, OID_802_11_SSID, &ssid, &len); + + if (rval) + device_printf (sc->ndis_dev, "set ssid failed: %d\n", rval); + return; } diff --git a/sys/dev/if_ndis/if_ndisvar.h b/sys/dev/if_ndis/if_ndisvar.h index c2bc6b6..2b2f47f 100644 --- a/sys/dev/if_ndis/if_ndisvar.h +++ b/sys/dev/if_ndis/if_ndisvar.h @@ -32,6 +32,9 @@ * $FreeBSD$ */ +#define NDIS_DEFAULT_NODENAME "FreeBSD NDIS node" +#define NDIS_NODENAME_LEN 32 + struct ndis_pci_type { uint16_t ndis_vid; uint16_t ndis_did; @@ -87,8 +90,8 @@ struct ndis_softc { struct resource *ndis_res_am; /* attribute mem (pccard) */ struct resource *ndis_res_cm; /* common mem (pccard) */ int ndis_rescnt; - struct mtx *ndis_mtx; - struct mtx *ndis_intrmtx; + struct mtx ndis_mtx; + struct mtx ndis_intrmtx; device_t ndis_dev; int ndis_unit; ndis_miniport_block ndis_block; @@ -124,6 +127,6 @@ struct ndis_softc { int ndis_mmapcnt; }; -#define NDIS_LOCK(_sc) mtx_pool_lock(ndis_mtxpool, (_sc)->ndis_mtx) -#define NDIS_UNLOCK(_sc) mtx_pool_unlock(ndis_mtxpool, (_sc)->ndis_mtx) +#define NDIS_LOCK(_sc) mtx_lock(&(_sc)->ndis_mtx) +#define NDIS_UNLOCK(_sc) mtx_unlock(&(_sc)->ndis_mtx) |