Subject: Re: arm32 raisespl
To: Ignatios Souvatzis <ignatios@cs.uni-bonn.de>
From: Richard Earnshaw <rearnsha@arm.com>
List: port-arm32
Date: 04/06/2000 16:36:09
This is a multipart MIME message.

--==_Exmh_-17874974750
Content-Type: text/plain; charset=us-ascii

> As far as I can tell, this, nonatomically,
> 
> compares old and new (skalar) level
> aborts if not higher
> stores new level
> calls machine dependent function to translate level to mask and store in
> right place
> 
> similar, for lowerspl().
> 
> Why is this safe to do?
> 

I don't think it is....



--==_Exmh_-17874974750
Content-Type: message/rfc822 ; name="1195"
Content-Description: 1195
Content-Disposition: attachment; filename="1195"

Delivery-Date: Tue Jun  1 12:42:52 1999
	id MAA20856; Tue, 1 Jun 1999 12:42:51 +0100 (BST)
	id AA14255; Tue, 1 Jun 99 12:42:50 BST
	id MAA20852; Tue, 1 Jun 1999 12:42:48 +0100 (BST)
	id MAA27556; Tue, 1 Jun 1999 12:42:46 +0100
Message-Id: <199906011142.MAA27556@sun52.NIS.cambridge>
To: mark@causality.com
Cc: richard.earnshaw@arm.com
Reply-To: richard.earnshaw@arm.com
Organization: ARM Ltd.
Subject: Re: Installing 1.4 
In-Reply-To: Your message of "Tue, 01 Jun 1999 10:54:16 BST."
             <Pine.SOL.3.96.990601105233.20029C-100000@fm3.facility.pipex.com> 
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Date: Tue, 01 Jun 1999 12:42:46 +0100
From: Richard Earnshaw <rearnsha@arm.com>
Content-Length: 2995

> Hmm, I'll see if I can find a printer to recreate this with. On the RiscPC
> I have never been able to create the problem so it does appear to be
> printer dependant. The lpt port is just part of a standard SMC superIO and
> just uses an attachment  to the dev/ic/lpt.c driver.
> 

If it's any help to know this, my printer is an Epson Stylus 600.

Probably not relevant, but whilst having a stare at the source trying to 
play mind games with what was going on, I think I've spotted a potential 
race in the raisespl code; perhaps you can convince me this can't happen:

        mov     r3, r0                  /* Save the new value */
        ldr     r1, Lcurrent_spl_level  /* Get the current spl level */
        ldr     r0, [r1]
        cmp     r3, r0
        movle   pc, lr

>From this point on, the SPL level is changed.  Interrupts are not disabled 
at this point (as far as I can tell), so can't an interrupt occur which 
could in turn (maybe indirectly -- context switch?) try to raise the spl 
level?  If so, and it is trying to raise it by not more than the current 
raise it will note that the spl level has changed and simply exit.  
However, since the thread really raising the spl has been suspended, the 
interrupts won't be completely masked.   As far as I can tell, the 
potential race lasts between here and the point in irq_setmasks that the 
code disables interrupts.

        str     r3, [r1]                /* Store the new spl level */

        ldr     r2, Lspl_masks          /* Get the spl mask */
        ldr     r2, [r2, r3, lsl #2]

        ldr     r1, Lspl_mask           /* Store in the current spl mask */
        str     r2, [r1]

        stmfd   sp!, {r0, lr}           /* Preserve registers */
        bl      _irq_setmasks           /* Update the actual masks */
        ldmfd   sp!, {r0, pc}           /* Exit */

If I'm right, then it would be possible for interrupts at a particular 
level to continue even if the code thinks that they are blocked.  The fix 
would be to always disable interrupts from before the store until after 
the masks have been updated.  Its possible that there is a similar issue 
with splx, though I think lowerspl is probably safe.

A possible fix is below (but not tested); I've also moved some 
instructions around to reduce the number of stalls on a StrongARM.

ENTRY(raisespl)
	ldr	r1, Lcurrent_spl_level	/* Get the current spl level */
	mov	r3, r0			/* Save the new value */
	ldr	r0, [r1]
	cmp	r3, r0
	movle	pc, lr

	mov	ip, r4			/* Put R4 somewhere safe */
	mrs	r4, cpsr_all		/* Disable interrupts */
	orr	r2, r4,  #(I32_bit)
	msr	cpsr_all, r2

	ldr	r2, Lspl_masks		/* Get the spl mask */
	str	r3, [r1]		/* Store the new spl level */

	ldr	r2, [r2, r3, lsl #2]

	ldr	r1, Lspl_mask		/* Store in the current spl mask */
	stmfd	sp!, {r0, ip, lr}	/* Preserve registers */
	str	r2, [r1]

	bl	_irq_setmasks		/* Update the actual masks */
	msr	cpsr_all, r4		/* Restore interrupt status */
	ldmfd	sp!, {r0, r4, pc}	/* Exit */



--==_Exmh_-17874974750--