Rewrite the ARM mutex implementation to be of the simple-mutex variety.
Because pre-v6 ARM lacks support for an atomic compare-and-swap, we implement _lock_cas() as a restartable atomic squence that is checked in the IRQ handler right before AST processing. (This is safe because, for all practical purposes, there are no SMP pre-v6 ARM systems.) This can serve as a model for other non-MP platforms that lack the necessary atomic operations for mutexes (SuperH, for example). Upshots of this change: - kmutex_t is now down to 8 bytes on ARM; about as good as we can get. - ARM2 systems don't have to trap and emulate SWP or SWPB for mutexes. The acorn26 port is not updated by this commit to do the LOCK_CAS_CHECK. That is left as an exercise for the port maintainer. Reviewed and tested by Matt Thomas.
This commit is contained in:
parent
b1c0dd5ffc
commit
165d4e6d83
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: arm_machdep.c,v 1.13 2007/02/09 21:55:02 ad Exp $ */
|
||||
/* $NetBSD: arm_machdep.c,v 1.14 2007/03/09 19:21:57 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 Wasabi Systems, Inc.
|
||||
@ -73,10 +73,11 @@
|
||||
|
||||
#include "opt_compat_netbsd.h"
|
||||
#include "opt_execfmt.h"
|
||||
#include "opt_arm_debug.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
__KERNEL_RCSID(0, "$NetBSD: arm_machdep.c,v 1.13 2007/02/09 21:55:02 ad Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: arm_machdep.c,v 1.14 2007/03/09 19:21:57 thorpej Exp $");
|
||||
|
||||
#include <sys/exec.h>
|
||||
#include <sys/proc.h>
|
||||
@ -84,6 +85,7 @@ __KERNEL_RCSID(0, "$NetBSD: arm_machdep.c,v 1.13 2007/02/09 21:55:02 ad Exp $");
|
||||
#include <sys/user.h>
|
||||
#include <sys/pool.h>
|
||||
#include <sys/ucontext.h>
|
||||
#include <sys/evcnt.h>
|
||||
|
||||
#include <arm/cpufunc.h>
|
||||
|
||||
@ -102,6 +104,24 @@ __KERNEL_RCSID(0, "$NetBSD: arm_machdep.c,v 1.13 2007/02/09 21:55:02 ad Exp $");
|
||||
*/
|
||||
vaddr_t vector_page;
|
||||
|
||||
#if defined(ARM_LOCK_CAS_DEBUG)
|
||||
/*
|
||||
* Event counters for tracking activity of the RAS-based _lock_cas()
|
||||
* routine.
|
||||
*/
|
||||
struct evcnt _lock_cas_restart =
|
||||
EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "_lock_cas", "restart");
|
||||
EVCNT_ATTACH_STATIC(_lock_cas_restart);
|
||||
|
||||
struct evcnt _lock_cas_success =
|
||||
EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "_lock_cas", "success");
|
||||
EVCNT_ATTACH_STATIC(_lock_cas_success);
|
||||
|
||||
struct evcnt _lock_cas_fail =
|
||||
EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "_lock_cas", "fail");
|
||||
EVCNT_ATTACH_STATIC(_lock_cas_fail);
|
||||
#endif /* ARM_LOCK_CAS_DEBUG */
|
||||
|
||||
/*
|
||||
* Clear registers on exec
|
||||
*/
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: genassym.cf,v 1.31 2007/02/20 00:05:14 matt Exp $
|
||||
# $NetBSD: genassym.cf,v 1.32 2007/03/09 19:21:57 thorpej Exp $
|
||||
|
||||
# Copyright (c) 1982, 1990 The Regents of the University of California.
|
||||
# All rights reserved.
|
||||
@ -142,6 +142,8 @@ define TF_R0 offsetof(struct trapframe, tf_r0)
|
||||
define TF_R10 offsetof(struct trapframe, tf_r10)
|
||||
define TF_PC offsetof(struct trapframe, tf_pc)
|
||||
|
||||
define IF_PC offsetof(struct irqframe, if_pc)
|
||||
|
||||
define PROCSIZE sizeof(struct proc)
|
||||
define TRAPFRAMESIZE sizeof(struct trapframe)
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: irq_dispatch.S,v 1.7 2005/12/11 12:16:41 christos Exp $ */
|
||||
/* $NetBSD: irq_dispatch.S,v 1.8 2007/03/09 19:21:58 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002 Fujitsu Component Limited
|
||||
@ -94,6 +94,8 @@
|
||||
.Lcurrent_intr_depth:
|
||||
.word _C_LABEL(current_intr_depth)
|
||||
|
||||
LOCK_CAS_CHECK_LOCALS
|
||||
|
||||
AST_ALIGNMENT_FAULT_LOCALS
|
||||
|
||||
ASENTRY_NP(irq_entry)
|
||||
@ -125,6 +127,8 @@ ASENTRY_NP(irq_entry)
|
||||
*/
|
||||
str r6, [r5]
|
||||
|
||||
LOCK_CAS_CHECK
|
||||
|
||||
DO_AST_AND_RESTORE_ALIGNMENT_FAULTS
|
||||
PULLFRAMEFROMSVCANDEXIT
|
||||
movs pc, lr /* Exit */
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: files.arm,v 1.82 2007/01/06 00:50:54 christos Exp $
|
||||
# $NetBSD: files.arm,v 1.83 2007/03/09 19:21:58 thorpej Exp $
|
||||
|
||||
# temporary define to allow easy moving to ../arch/arm/arm32
|
||||
defflag ARM32
|
||||
@ -23,6 +23,9 @@ defflag opt_cpuoptions.h ARM9_CACHE_WRITE_THROUGH
|
||||
# Interrupt implementation header definition.
|
||||
defparam opt_arm_intr_impl.h ARM_INTR_IMPL
|
||||
|
||||
# ARM-specific debug options
|
||||
defflag opt_arm_debug.h ARM_LOCK_CAS_DEBUG
|
||||
|
||||
# Board-specific bus_space(9) definitions
|
||||
defflag opt_arm_bus_space.h __BUS_SPACE_HAS_STREAM_METHODS
|
||||
|
||||
@ -115,6 +118,7 @@ file arch/arm/arm/cpufunc_asm_xscale.S cpu_xscale_80200 |
|
||||
cpu_xscale_pxa250 |
|
||||
cpu_xscale_pxa270
|
||||
file arch/arm/arm/cpufunc_asm_ixp12x0.S cpu_ixp12x0
|
||||
file arch/arm/arm/lock_cas.S
|
||||
file arch/arm/arm/process_machdep.c
|
||||
file arch/arm/arm/procfs_machdep.c procfs
|
||||
file arch/arm/arm/sig_machdep.c
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: frame.h,v 1.14 2006/09/27 21:42:05 manu Exp $ */
|
||||
/* $NetBSD: frame.h,v 1.15 2007/03/09 19:21:58 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994-1997 Mark Brinicombe.
|
||||
@ -111,6 +111,7 @@ void validate_trapframe __P((trapframe_t *, int));
|
||||
#include "opt_compat_netbsd.h"
|
||||
#include "opt_execfmt.h"
|
||||
#include "opt_multiprocessor.h"
|
||||
#include "opt_arm_debug.h"
|
||||
|
||||
/*
|
||||
* AST_ALIGNMENT_FAULT_LOCALS and ENABLE_ALIGNMENT_FAULTS
|
||||
@ -267,6 +268,55 @@ void validate_trapframe __P((trapframe_t *, int));
|
||||
2:
|
||||
#endif /* EXEC_AOUT */
|
||||
|
||||
#ifdef ARM_LOCK_CAS_DEBUG
|
||||
#define LOCK_CAS_DEBUG_LOCALS \
|
||||
.L_lock_cas_restart: ;\
|
||||
.word _C_LABEL(_lock_cas_restart)
|
||||
|
||||
#if defined(__ARMEB__)
|
||||
#define LOCK_CAS_DEBUG_COUNT_RESTART \
|
||||
ble 99f ;\
|
||||
ldr r0, .L_lock_cas_restart ;\
|
||||
ldmia r0, {r1-r2} /* load ev_count */ ;\
|
||||
adds r2, r2, #1 /* 64-bit incr (lo) */ ;\
|
||||
adc r1, r1, #0 /* 64-bit incr (hi) */ ;\
|
||||
stmia r0, {r1-r2} /* store ev_count */
|
||||
#else /* __ARMEB__ */
|
||||
#define LOCK_CAS_DEBUG_COUNT_RESTART \
|
||||
ble 99f ;\
|
||||
ldr r0, .L_lock_cas_restart ;\
|
||||
ldmia r0, {r1-r2} /* load ev_count */ ;\
|
||||
adds r1, r1, #1 /* 64-bit incr (lo) */ ;\
|
||||
adc r2, r2, #0 /* 64-bit incr (hi) */ ;\
|
||||
stmia r0, {r1-r2} /* store ev_count */
|
||||
#endif /* __ARMEB__ */
|
||||
#else /* ARM_LOCK_CAS_DEBUG */
|
||||
#define LOCK_CAS_DEBUG_LOCALS /* nothing */
|
||||
#define LOCK_CAS_DEBUG_COUNT_RESTART /* nothing */
|
||||
#endif /* ARM_LOCK_CAS_DEBUG */
|
||||
|
||||
#define LOCK_CAS_CHECK_LOCALS \
|
||||
.L_lock_cas: ;\
|
||||
.word _C_LABEL(_lock_cas) ;\
|
||||
.L_lock_cas_end: ;\
|
||||
.word _C_LABEL(_lock_cas_end) ;\
|
||||
LOCK_CAS_DEBUG_LOCALS
|
||||
|
||||
#define LOCK_CAS_CHECK \
|
||||
ldr r0, [sp] /* get saved PSR */ ;\
|
||||
and r0, r0, #(PSR_MODE) /* check for SVC32 mode */ ;\
|
||||
teq r0, #(PSR_SVC32_MODE) ;\
|
||||
bne 99f /* nope, get out now */ ;\
|
||||
ldr r0, [sp, #(IF_PC)] ;\
|
||||
ldr r1, .L_lock_cas_end ;\
|
||||
cmp r0, r1 ;\
|
||||
bge 99f ;\
|
||||
ldr r1, .L_lock_cas ;\
|
||||
cmp r0, r1 ;\
|
||||
strgt r1, [sp, #(IF_PC)] ;\
|
||||
LOCK_CAS_DEBUG_COUNT_RESTART ;\
|
||||
99:
|
||||
|
||||
/*
|
||||
* ASM macros for pushing and pulling trapframes from the stack
|
||||
*
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: mutex.h,v 1.6 2007/03/09 11:30:28 skrll Exp $ */
|
||||
/* $NetBSD: mutex.h,v 1.7 2007/03/09 19:21:58 thorpej Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2002, 2007 The NetBSD Foundation, Inc.
|
||||
@ -41,155 +41,68 @@
|
||||
|
||||
/*
|
||||
* The ARM mutex implementation is troublesome, because pre-v6 ARM lacks a
|
||||
* compare-and-set operation. However, there aren't any MP pre-v6 ARM
|
||||
* compare-and-swap operation. However, there aren't any MP pre-v6 ARM
|
||||
* systems to speak of. We are mostly concerned with atomicity with respect
|
||||
* to interrupts.
|
||||
*
|
||||
* SMP for spin mutexes is easy - we don't need to know who owns the lock.
|
||||
* For adaptive mutexes, we need an additional interlock.
|
||||
* ARMv6, however, does have ldrex/strex, and can thus implement an MP-safe
|
||||
* compare-and-swap.
|
||||
*
|
||||
* Unfortunately, not all ARM kernels are linked at the same address,
|
||||
* meaning we cannot safely overlay the interlock with the MSB of the
|
||||
* owner field.
|
||||
*
|
||||
* For a mutex acquisition, we first grab the interlock and then set the
|
||||
* owner field.
|
||||
*
|
||||
* There is room in the owners field for a waiters bit, but we don't do
|
||||
* that because it would be hard to synchronize using one without a CAS
|
||||
* operation. Because the waiters bit is only needed for adaptive mutexes,
|
||||
* we instead use the lock that is normally used by spin mutexes to indicate
|
||||
* waiters.
|
||||
*
|
||||
* Spin mutexes are initialized with the interlock held to cause the
|
||||
* assembly stub to go through mutex_vector_enter().
|
||||
*
|
||||
* When releasing an adaptive mutex, we first clear the owners field, and
|
||||
* then check to see if the waiters byte is set. This ensures that there
|
||||
* will always be someone to wake any sleeping waiters up (even it the mutex
|
||||
* is acquired immediately after we release it, or if we are preempted
|
||||
* immediatley after clearing the owners field). The setting or clearing of
|
||||
* the waiters byte is serialized by the turnstile chain lock associated
|
||||
* with the mutex.
|
||||
*
|
||||
* See comments in kern_mutex.c about releasing adaptive mutexes without
|
||||
* an interlocking step.
|
||||
* So, what we have done is impement simple mutexes using a compare-and-swap.
|
||||
* We support pre-ARMv6 by implementing _lock_cas() as a restartable atomic
|
||||
* sequence that is checked by the IRQ vector. MP-safe ARMv6 support will
|
||||
* be added later.
|
||||
*/
|
||||
|
||||
#ifndef __MUTEX_PRIVATE
|
||||
|
||||
struct kmutex {
|
||||
uintptr_t mtx_pad1;
|
||||
uint32_t mtx_pad2[2];
|
||||
uint32_t mtx_pad2;
|
||||
};
|
||||
|
||||
#else /* __MUTEX_PRIVATE */
|
||||
|
||||
struct kmutex {
|
||||
volatile uintptr_t mtx_owner; /* 0-3 */
|
||||
__cpu_simple_lock_t mtx_interlock; /* 4 */
|
||||
__cpu_simple_lock_t mtx_lock; /* 5 */
|
||||
ipl_cookie_t mtx_ipl; /* 6 */
|
||||
uint8_t mtx_pad; /* 7 */
|
||||
uint32_t mtx_id; /* 8-11 */
|
||||
union {
|
||||
/* Adaptive mutex */
|
||||
volatile uintptr_t mtxa_owner; /* 0-3 */
|
||||
|
||||
/* Spin mutex */
|
||||
struct {
|
||||
volatile uint8_t mtxs_dummy;
|
||||
ipl_cookie_t mtxs_ipl;
|
||||
__cpu_simple_lock_t mtxs_lock;
|
||||
volatile uint8_t mtxs_unused;
|
||||
} s;
|
||||
} u;
|
||||
volatile uint32_t mtx_id; /* 4-7 */
|
||||
};
|
||||
|
||||
#define mtx_owner u.mtxa_owner
|
||||
#define mtx_ipl u.s.mtxs_ipl
|
||||
#define mtx_lock u.s.mtxs_lock
|
||||
|
||||
#if 0
|
||||
#define __HAVE_MUTEX_STUBS 1
|
||||
#define __HAVE_SPIN_MUTEX_STUBS 1
|
||||
#define __HAVE_MUTEX_STUBS 1
|
||||
#define __HAVE_SPIN_MUTEX_STUBS 1
|
||||
#endif
|
||||
#define __HAVE_SIMPLE_MUTEXES 1
|
||||
|
||||
static inline uintptr_t
|
||||
MUTEX_OWNER(uintptr_t owner)
|
||||
{
|
||||
return owner;
|
||||
}
|
||||
/*
|
||||
* MUTEX_RECEIVE: no memory barrier required; we're synchronizing against
|
||||
* interrupts, not multiple processors.
|
||||
*/
|
||||
#define MUTEX_RECEIVE(mtx) /* nothing */
|
||||
|
||||
static inline int
|
||||
MUTEX_OWNED(uintptr_t owner)
|
||||
{
|
||||
return owner != 0;
|
||||
}
|
||||
/*
|
||||
* MUTEX_GIVE: no memory barrier required; same reason.
|
||||
*/
|
||||
#define MUTEX_GIVE(mtx) /* nothing */
|
||||
|
||||
static inline int
|
||||
MUTEX_SET_WAITERS(kmutex_t *mtx, uintptr_t owner)
|
||||
{
|
||||
(void)__cpu_simple_lock_try(&mtx->mtx_lock);
|
||||
return mtx->mtx_owner != 0;
|
||||
}
|
||||
bool _lock_cas(volatile uintptr_t *, uintptr_t, uintptr_t);
|
||||
|
||||
static inline void
|
||||
MUTEX_CLEAR_WAITERS(kmutex_t *mtx)
|
||||
{
|
||||
__cpu_simple_unlock(&mtx->mtx_lock);
|
||||
}
|
||||
|
||||
static inline int
|
||||
MUTEX_HAS_WAITERS(volatile kmutex_t *mtx)
|
||||
{
|
||||
if (mtx->mtx_owner == 0)
|
||||
return 0;
|
||||
return mtx->mtx_lock == __SIMPLELOCK_LOCKED;
|
||||
}
|
||||
|
||||
static inline void
|
||||
MUTEX_INITIALIZE_SPIN(kmutex_t *mtx, u_int id, int ipl)
|
||||
{
|
||||
mtx->mtx_id = (id << 1) | 1;
|
||||
mtx->mtx_ipl = makeiplcookie(ipl);
|
||||
mtx->mtx_interlock = __SIMPLELOCK_LOCKED;
|
||||
__cpu_simple_lock_init(&mtx->mtx_lock);
|
||||
}
|
||||
|
||||
static inline void
|
||||
MUTEX_INITIALIZE_ADAPTIVE(kmutex_t *mtx, u_int id)
|
||||
{
|
||||
mtx->mtx_id = (id << 1) | 0;
|
||||
__cpu_simple_lock_init(&mtx->mtx_interlock);
|
||||
__cpu_simple_lock_init(&mtx->mtx_lock);
|
||||
}
|
||||
|
||||
static inline void
|
||||
MUTEX_DESTROY(kmutex_t *mtx)
|
||||
{
|
||||
mtx->mtx_owner = (uintptr_t)-1L;
|
||||
mtx->mtx_id = ~0;
|
||||
}
|
||||
|
||||
static inline u_int
|
||||
MUTEX_GETID(kmutex_t *mtx)
|
||||
{
|
||||
return mtx->mtx_id >> 1;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
MUTEX_SPIN_P(volatile kmutex_t *mtx)
|
||||
{
|
||||
return (mtx->mtx_id & 1) == 1;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
MUTEX_ADAPTIVE_P(volatile kmutex_t *mtx)
|
||||
{
|
||||
return (mtx->mtx_id & 1) == 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
MUTEX_ACQUIRE(kmutex_t *mtx, uintptr_t curthread)
|
||||
{
|
||||
if (!__cpu_simple_lock_try(&mtx->mtx_interlock))
|
||||
return 0;
|
||||
mtx->mtx_owner = curthread;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
MUTEX_RELEASE(kmutex_t *mtx)
|
||||
{
|
||||
mtx->mtx_owner = 0;
|
||||
__cpu_simple_unlock(&mtx->mtx_lock);
|
||||
__cpu_simple_unlock(&mtx->mtx_interlock);
|
||||
}
|
||||
#define MUTEX_CAS(p, o, n) _lock_cas((p), (o), (n))
|
||||
|
||||
#endif /* __MUTEX_PRIVATE */
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: iomd_irq.S,v 1.5 2005/12/11 12:16:47 christos Exp $ */
|
||||
/* $NetBSD: iomd_irq.S,v 1.6 2007/03/09 19:21:58 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994-1998 Mark Brinicombe.
|
||||
@ -96,6 +96,8 @@ Lcurrent_intr_depth:
|
||||
Lspl_masks:
|
||||
.word _C_LABEL(spl_masks)
|
||||
|
||||
LOCK_CAS_CHECK_LOCALS
|
||||
|
||||
AST_ALIGNMENT_FAULT_LOCALS
|
||||
|
||||
/*
|
||||
@ -337,6 +339,8 @@ exitirq:
|
||||
sub r1, r1, #1
|
||||
str r1, [r0]
|
||||
|
||||
LOCK_CAS_CHECK
|
||||
|
||||
DO_AST_AND_RESTORE_ALIGNMENT_FAULTS
|
||||
PULLFRAMEFROMSVCANDEXIT
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: ofw_irq.S,v 1.6 2007/03/08 20:48:39 matt Exp $ */
|
||||
/* $NetBSD: ofw_irq.S,v 1.7 2007/03/09 19:21:59 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994-1998 Mark Brinicombe.
|
||||
@ -93,6 +93,8 @@ Lirq_entry:
|
||||
Lofwirqstk: /* hack */
|
||||
.word ofwirqstk + 4096
|
||||
|
||||
LOCK_CAS_CHECK_LOCALS
|
||||
|
||||
AST_ALIGNMENT_FAULT_LOCALS
|
||||
|
||||
/*
|
||||
@ -325,6 +327,8 @@ nextirq:
|
||||
sub r1, r1, #1
|
||||
str r1, [r0]
|
||||
|
||||
LOCK_CAS_CHECK
|
||||
|
||||
DO_AST_AND_RESTORE_ALIGNMENT_FAULTS
|
||||
PULLFRAMEFROMSVCANDEXIT
|
||||
movs pc, lr /* Exit */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: sa11x0_irq.S,v 1.9 2006/03/05 11:30:58 peter Exp $ */
|
||||
/* $NetBSD: sa11x0_irq.S,v 1.10 2007/03/09 19:21:59 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 Mark Brinicombe.
|
||||
@ -67,6 +67,8 @@ Ldbg_str:
|
||||
.asciz "irq_entry %x %x\n"
|
||||
#endif
|
||||
|
||||
LOCK_CAS_CHECK_LOCALS
|
||||
|
||||
AST_ALIGNMENT_FAULT_LOCALS
|
||||
|
||||
/*
|
||||
@ -244,6 +246,8 @@ nextirq:
|
||||
sub r1, r1, #1
|
||||
str r1, [r0]
|
||||
|
||||
LOCK_CAS_CHECK
|
||||
|
||||
DO_AST_AND_RESTORE_ALIGNMENT_FAULTS
|
||||
PULLFRAMEFROMSVCANDEXIT
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: i80200_irq.S,v 1.13 2005/12/11 12:16:51 christos Exp $ */
|
||||
/* $NetBSD: i80200_irq.S,v 1.14 2007/03/09 19:21:59 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002 Wasabi Systems, Inc.
|
||||
@ -65,6 +65,8 @@
|
||||
.word _C_LABEL(xscale_pmc_dispatch)
|
||||
#endif
|
||||
|
||||
LOCK_CAS_CHECK_LOCALS
|
||||
|
||||
AST_ALIGNMENT_FAULT_LOCALS
|
||||
|
||||
ASENTRY_NP(irq_entry)
|
||||
@ -128,6 +130,8 @@ ASENTRY_NP(irq_entry)
|
||||
sub r1, r1, #1
|
||||
str r1, [r0]
|
||||
|
||||
LOCK_CAS_CHECK
|
||||
|
||||
DO_AST_AND_RESTORE_ALIGNMENT_FAULTS
|
||||
PULLFRAMEFROMSVCANDEXIT
|
||||
movs pc, lr /* Exit */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: isa_irq.S,v 1.6 2007/03/08 20:48:39 matt Exp $ */
|
||||
/* $NetBSD: isa_irq.S,v 1.7 2007/03/09 19:21:59 thorpej Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright 1997
|
||||
@ -289,6 +289,8 @@ nextirq:
|
||||
sub r1, r1, #1
|
||||
str r1, [r0]
|
||||
|
||||
LOCK_CAS_CHECK
|
||||
|
||||
DO_AST_AND_RESTORE_ALIGNMENT_FAULTS
|
||||
PULLFRAMEFROMSVCANDEXIT
|
||||
|
||||
@ -301,6 +303,8 @@ Lspl_mask:
|
||||
Lcurrent_mask:
|
||||
.word _C_LABEL(current_mask) /* irq's that are usable */
|
||||
|
||||
LOCK_CAS_CHECK_LOCALS
|
||||
|
||||
AST_ALIGNMENT_FAULT_LOCALS
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user