From rea@rea.mbslab.kiae.ru  Wed Jun  1 15:15:52 2005
Return-Path: <rea@rea.mbslab.kiae.ru>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id 941C716A41C
	for <FreeBSD-gnats-submit@freebsd.org>; Wed,  1 Jun 2005 15:15:52 +0000 (GMT)
	(envelope-from rea@rea.mbslab.kiae.ru)
Received: from rea.mbslab.kiae.ru (rea.mbslab.kiae.ru [144.206.177.25])
	by mx1.FreeBSD.org (Postfix) with ESMTP id 3AE6443D53
	for <FreeBSD-gnats-submit@freebsd.org>; Wed,  1 Jun 2005 15:15:52 +0000 (GMT)
	(envelope-from rea@rea.mbslab.kiae.ru)
Received: from rea.mbslab.kiae.ru (localhost [127.0.0.1])
	by rea.mbslab.kiae.ru (Postfix) with ESMTP id 5FE00B8ED
	for <FreeBSD-gnats-submit@freebsd.org>; Wed,  1 Jun 2005 19:15:50 +0400 (MSD)
Received: by rea.mbslab.kiae.ru (Postfix, from userid 1000)
	id 3947BB8DB; Wed,  1 Jun 2005 19:15:50 +0400 (MSD)
Message-Id: <20050601151550.GC66404@rea.mbslab.kiae.ru>
Date: Wed, 1 Jun 2005 19:15:50 +0400
From: "Eygene A. Ryabinkin" <rea@rea.mbslab.kiae.ru>
To: FreeBSD-gnats-submit@freebsd.org
Subject: ndis driver does not compile into kernel
X-Send-Pr-Version: 3.113

>Number:         81767
>Category:       kern
>Synopsis:       [patch] ndis driver does not compile into kernel
>Confidential:   no
>Severity:       critical
>Priority:       medium
>Responsible:    rik
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Jun 01 15:20:01 GMT 2005
>Closed-Date:    Mon Jul 11 08:36:06 GMT 2005
>Last-Modified:  Mon Jul 11 08:36:06 GMT 2005
>Originator:     Eygene A. Ryabinkin
>Release:        FreeBSD 6.0-CURRENT i386
>Organization:
Code Labs
>Environment:
System: FreeBSD visitor-169432 6.0-CURRENT FreeBSD 6.0-CURRENT #9: Wed Jun 1 18:36:49 MSD 2005 rea@visitor-169432:/usr/obj/usr/src/sys/TWILIGHT i386


>Description:
 If we specify 'device ndis' and 'options NDISAPI' in kernel configuration
file, then we will not be able to build such kernel due to a syntaxical errors
in file /sys/compat/ndis/subr_ntoskrnl.c
>How-To-Repeat:
 Cvsup 6.0-CURRENT, put
options NDISAPI
device ndis
device wlan
 into kernel config and build a kernel. The compiler will spit a bunch of errors
for subr_ntoskrnl.c
>Fix:
 Just specify explicit typecast of dpc->k_lock in KeRemoveQueueDpc()

--- subr_ntoskrnl.c.orig        Wed Jun  1 18:28:11 2005
+++ subr_ntoskrnl.c     Wed Jun  1 18:31:10 2005
@@ -3110,15 +3110,15 @@
        if (dpc->k_lock == NULL)
                return(FALSE);
 
-       mtx_lock_spin(dpc->k_lock);
+       mtx_lock_spin((struct mtx *)(dpc->k_lock));
        if (dpc->k_dpclistentry.nle_flink == &dpc->k_dpclistentry) {
-               mtx_unlock_spin(dpc->k_lock);
+               mtx_unlock_spin((struct mtx *)(dpc->k_lock));
                return(FALSE);
        }
 
        REMOVE_LIST_ENTRY((&dpc->k_dpclistentry));
        INIT_LIST_HEAD((&dpc->k_dpclistentry));
-       mtx_unlock_spin(dpc->k_lock);
+       mtx_unlock_spin((struct mtx *)(dpc->k_lock));
 
        return(TRUE);
 }

-- 
 rea
>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->wpaul 
Responsible-Changed-By: rik 
Responsible-Changed-When: Wed Jun 8 14:38:17 GMT 2005 
Responsible-Changed-Why:  
Assign PR to the author. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=81767 

From: "Eygene A. Ryabinkin" <rea@rea.mbslab.kiae.ru>
To: bug-followup@FreeBSD.org, rea@rea.mbslab.kiae.ru
Cc:  
Subject: Re: kern/81767: [patch] ndis driver does not compile into kernel
Date: Sat, 25 Jun 2005 21:53:02 +0400

  More investigations:
 --------------------------------------------------------------------------------
  Bug in subr_ntoskrnl.c: dereferencing a (void*) in KeRemoveQueueDpc() when ndis
 is compiled as a kernel built-in object. But no (void*) dereferencing for
 kernel module compilation.
 
  Description: functions (actually macros) mtx_lock_spin and mtx_unlock_spin
 in KeRemoveQueueDpc() are taking dpc->k_lock as their argument. The variable
 dpc is of type (kdpc*). 'struct kdpc' (kernel deferred procedure call)
 is defined in /sys/compat/ndis/ntoskrnl_var.h (from line 359):
 -----
 struct kdpc {
         uint16_t                k_type;
         uint8_t                 k_num;          /* CPU number */
         uint8_t                 k_importance;   /* priority */
         list_entry              k_dpclistentry;
         void                    *k_deferedfunc;
         void                    *k_deferredctx;
         void                    *k_sysarg1;
         void                    *k_sysarg2;
         void                    *k_lock;
 };
 -----
  So, dpc->k_lock is of type (void*).
 
  When it compiles as a module we have the following definition for
 mtx_lock_spin:
 #define mtx_lock_spin_flags(m,opts) _mtx_lock_spin_flags((m), (opts), LOCK_FILE, LOCK_LINE)
 But when we compile it as the kernel built-in, it becomes
 #define mtx_lock_spin_flags(m,opts) _get_spin_lock((m), curthread, (opts), LOCK_
 FILE, LOCK_LINE)
 
  This distinction comes from /sys/sys/mutex.h (from line 298):
 -----
 #if LOCK_DEBUG > 0 || defined(MUTEX_NOINLINE)
 #define mtx_lock_flags(m, opts)                                         \
         _mtx_lock_flags((m), (opts), LOCK_FILE, LOCK_LINE)
 #define mtx_unlock_flags(m, opts)                                       \
         _mtx_unlock_flags((m), (opts), LOCK_FILE, LOCK_LINE)
 #define mtx_lock_spin_flags(m, opts)                                    \
         _mtx_lock_spin_flags((m), (opts), LOCK_FILE, LOCK_LINE)
 #define mtx_unlock_spin_flags(m, opts)                                  \
         _mtx_unlock_spin_flags((m), (opts), LOCK_FILE, LOCK_LINE)
 #else   /* LOCK_DEBUG == 0 && !MUTEX_NOINLINE */
 #define mtx_lock_flags(m, opts)                                         \
         _get_sleep_lock((m), curthread, (opts), LOCK_FILE, LOCK_LINE)
 #define mtx_unlock_flags(m, opts)                                       \
         _rel_sleep_lock((m), curthread, (opts), LOCK_FILE, LOCK_LINE)
 #define mtx_lock_spin_flags(m, opts)                                    \
         _get_spin_lock((m), curthread, (opts), LOCK_FILE, LOCK_LINE)
 #define mtx_unlock_spin_flags(m, opts)                                  \
         _rel_spin_lock((m))
 #endif  /* LOCK_DEBUG > 0 || MUTEX_NOINLINE */
 -----
  And in kernel compilation I have LOCK_DEBUG defined as 0, while for module
 compilation it equals to 1. That's the cause of distinct behaviour.
 
  The first case: module compilation. _mtx_lock_spin_flags is defined in
 /sys/sys/mutex.h as (from line 114)
 -----
 void    _mtx_lock_spin_flags(struct mtx *m, int opts, const char *file,
              int line);
 -----
 So, our (void*) is implicitely cast to (struct mtx*).
  The second, worst case: kernel built-in. _get_spin_lock is defined in
 /sys/sys/mutex.h as (from line 165)
 -----
 #ifndef _get_spin_lock
 #ifdef SMP
 #define _get_spin_lock(mp, tid, opts, file, line) do {                  \
         struct thread *_tid = (tid);                                    \
                                                                         \
         spinlock_enter();                                               \
         if (!_obtain_lock((mp), _tid)) {                                \
                 if ((mp)->mtx_lock == (uintptr_t)_tid)                  \
                         (mp)->mtx_recurse++;                            \
                 else                                                    \
                         _mtx_lock_spin((mp), _tid, (opts), (file), (line)); \
         }                                                               \
 } while (0)
 #else /* SMP */
 #define _get_spin_lock(mp, tid, opts, file, line) do {                  \
         struct thread *_tid = (tid);                                    \
                                                                         \
         spinlock_enter();                                               \
         if ((mp)->mtx_lock == (uintptr_t)_tid)                          \
                 (mp)->mtx_recurse++;                                    \
         else {                                                          \
                 KASSERT((mp)->mtx_lock == MTX_UNOWNED, ("corrupt spinlock")); \
                 (mp)->mtx_lock = (uintptr_t)_tid;                       \
         }                                                               \
 } while (0)
 #endif /* SMP */
 #endif
 -----
 Here we are branching: with SMP undefined, our (void*) is dereferenced as
 (dpc->k_lock)->mtx_lock and (dpc->k_lock)->mtx_recurse. It is surely the sign
 of 'struct mtx*', but here we need an explicit typecast.
  When symbol SMP is defined, we pass our pointer to atomic_cmpset_ptr() as
 &(dpc->k_lock)->mtx_lock (/sys/sys/mutex.h, line 128):
 -----
 #ifndef _obtain_lock
 #define _obtain_lock(mp, tid)                                           \
         atomic_cmpset_acq_ptr(&(mp)->mtx_lock, (void *)MTX_UNOWNED, (tid))
 #endif
 -----
  And again it must be 'struct mtx*' here. As a side note: it is better to write
 -----
 atomic_cmpset_acq_ptr(&((mp)->mtx_lock), (void *)MTX_UNOWNED, (tid))
 -----
 for those people who forgot that damned precedence order in C language.
 
  So, if one is read through this junk he must believe that our poor (void*)
 must be typecasted explicitely to 'struct mtx*'. And the proposed patch just
 does it:
 --- subr_ntoskrnl.c.orig	Wed Jun  1 18:28:11 2005
 +++ subr_ntoskrnl.c	Wed Jun  1 18:31:10 2005
 @@ -3110,15 +3110,15 @@
  	if (dpc->k_lock == NULL)
  		return(FALSE);
  
 -	mtx_lock_spin(dpc->k_lock);
 +	mtx_lock_spin((struct mtx *)(dpc->k_lock));
  	if (dpc->k_dpclistentry.nle_flink == &dpc->k_dpclistentry) {
 -		mtx_unlock_spin(dpc->k_lock);
 +		mtx_unlock_spin((struct mtx *)(dpc->k_lock));
  		return(FALSE);
  	}
  
  	REMOVE_LIST_ENTRY((&dpc->k_dpclistentry));
  	INIT_LIST_HEAD((&dpc->k_dpclistentry));
 -	mtx_unlock_spin(dpc->k_lock);
 +	mtx_unlock_spin((struct mtx *)(dpc->k_lock));
  
  	return(TRUE);
  }
 
  <Applause here>
 -- 
  rea
Responsible-Changed-From-To: wpaul->rik 
Responsible-Changed-By: rik 
Responsible-Changed-When: Sat Jul 9 13:10:52 GMT 2005 
Responsible-Changed-Why:  
I will take care of it. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=81767 
State-Changed-From-To: open->patched 
State-Changed-By: rik 
State-Changed-When: Sat Jul 9 13:15:02 GMT 2005 
State-Changed-Why:  
Commited, please test. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=81767 

From: "Eygene A. Ryabinkin" <freebsd@rea.mbslab.kiae.ru>
To: Roman Kurakin <rik@FreeBSD.org>
Cc: bug-followup@FreeBSD.org, rea@rea.mbslab.kiae.ru
Subject: Re: kern/81767: [patch] ndis driver does not compile into kernel
Date: Mon, 11 Jul 2005 08:07:23 +0400

  Works fine for me, thanks a lot!
 -- 
  rea

From: "Eygene A. Ryabinkin" <rea@rea.mbslab.kiae.ru>
To: bug-followup@FreeBSD.org, rea@rea.mbslab.kiae.ru
Cc:  
Subject: Re: kern/81767: [patch] ndis driver does not compile into kernel
Date: Mon, 11 Jul 2005 08:08:49 +0400

  Works fine for me, thanks a lot!
 -- 
  rea
State-Changed-From-To: patched->closed 
State-Changed-By: rik 
State-Changed-When: Mon Jul 11 08:35:10 GMT 2005 
State-Changed-Why:  
All done. Case is closed. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=81767 
>Unformatted:
