196 lines
8.3 KiB
NASM
196 lines
8.3 KiB
NASM
; title "Interlocked Operations"
|
|
;++
|
|
;
|
|
; Copyright (c) Microsoft Corporation
|
|
;
|
|
; Module Name:
|
|
;
|
|
; intrlock.asm
|
|
;
|
|
; Abstract:
|
|
;
|
|
; This module implements the 32 and 16 bit interlocked operations for ARMv6 and beyond.
|
|
; The instructions used in this module for gaining exclusive access to a memory location
|
|
; arent supported in ARMv5 and earlier
|
|
;
|
|
; The functions aren't optimized because these are brand new instructions that we dont
|
|
; understand completely. That should be done after profiling and understanding their behavior.
|
|
;
|
|
; This whole file will be discarded when the intrinsics come in.
|
|
;
|
|
; Environment:
|
|
;
|
|
; Kernel and User mode.
|
|
;
|
|
;--
|
|
|
|
#include "ksarm.h"
|
|
|
|
#if defined(_ARM_WORKAROUND_)
|
|
; The LDREXH, STREXH, LDREXD, STREXD and CLREX instructions arent supported
|
|
; by the current assembler. Remove this and replace with the actual instructions
|
|
; when the assembler supports it
|
|
; This is not a generic assembler so I am explicitly defining values only for the
|
|
; instructions I am using
|
|
|
|
|
|
#define LDREXH_R12_R0 0xE1F0CF9F ;ldrexh r12, [r0] (1110 0001 1111 0000 1100 1111 1001 1111)
|
|
#define STREXHEQ_R3_R1_R0 0x01E03F91 ;strexheq r3, r1, [r0] (0000 0001 1110 0000 0011 1111 1001 0001)
|
|
#define STREXH_R3_R12_R0 0xE1E03F9C ;strexh r3, r12, [r0] (1110 0001 1110 0000 0011 1111 1001 1100)
|
|
#define LDREXD_R4_R0 0xE1B04F9F ;ldrexd r4, [r0] (1110 0001 1011 0000 0100 1111 1001 1111)
|
|
#define STREXDEQ_R2_R6_R0 0x01A02F96 ;strexdeq r2, r6, [r0] (0000 0001 1010 0000 0010 1111 1001 0110)
|
|
|
|
#define CLREX 0xF57FF01F ; clrex (1111 0101 0111 1111 1111 0000 0001 1111)
|
|
|
|
#endif
|
|
|
|
|
|
TEXTAREA
|
|
|
|
LEAF_ENTRY InterlockedExchange
|
|
1 ldrex r12, [r0] ; load from the address and mark it exclusive
|
|
strex r3, r1, [r0] ; attempt to store the new value
|
|
cmp r3, #1 ; check if the store failed (0=success, 1=failure)
|
|
beq %B1 ; restart if the store failed
|
|
mov r0, r12 ; return the original value
|
|
mov pc, lr
|
|
LEAF_END
|
|
|
|
LEAF_ENTRY InterlockedCompareExchange
|
|
1 ldrex r12, [r0] ; load from the address and mark it exclusive
|
|
cmp r12, r2 ; compare the value with the comperand(r2)
|
|
strexeq r3, r1, [r0] ; if they were equal, attempt to store the new value (r1)
|
|
bne %F2 ; if they were not equal jump to (2) which clears the exclusive tag on the address and returns
|
|
cmp r3, #1 ; check the status of the store (returned in r3)
|
|
beq %B1 ; go back to the start if it failed (0=success, 1=failure)
|
|
bne %F3 ; if it succeeded, jump to (3) and return. there is no need to clrex if strex succeeded
|
|
2 dcd CLREX ; clrex
|
|
3 mov r0, r12
|
|
mov pc, lr
|
|
LEAF_END
|
|
|
|
LEAF_ENTRY InterlockedCompareExchange16 ; has the same structure as InterlockedCompareExchange, but uses half word operands
|
|
1 dcd LDREXH_R12_R0
|
|
cmp r12, r2
|
|
dcd STREXHEQ_R3_R1_R0
|
|
bne %F2
|
|
cmp r3, #1
|
|
beq %B1
|
|
bne %F3
|
|
2 dcd CLREX ; clrex
|
|
3 mov r0, r12
|
|
mov pc, lr
|
|
LEAF_END
|
|
|
|
LEAF_ENTRY InterlockedIncrement
|
|
1 ldrex r12, [r0] ; load from the address and mark it exclusive
|
|
add r12, r12, #1 ; increment it
|
|
strex r3, r12, [r0] ; attempt to store the new value
|
|
cmp r3, #1 ; check if it succeeded (0=success, 1=failure)
|
|
beq %B1 ; loop if it failed
|
|
mov r0, r12 ; return the increment value if it succeeded
|
|
mov pc, lr
|
|
LEAF_END
|
|
|
|
LEAF_ENTRY InterlockedIncrement16 ; has the same structure as InterlockedIncrement, but uses half word operands
|
|
1 dcd LDREXH_R12_R0
|
|
add r12, r12, #1
|
|
dcd STREXH_R3_R12_R0
|
|
cmp r3, #1
|
|
beq %B1
|
|
mov r0, r12
|
|
mov pc, lr
|
|
LEAF_END
|
|
|
|
LEAF_ENTRY InterlockedDecrement ; has the same structure as InterlockedIncrement
|
|
1 ldrex r12, [r0]
|
|
sub r12, r12, #1
|
|
strex r3, r12, [r0]
|
|
cmp r3, #1
|
|
beq %B1
|
|
mov r0, r12
|
|
mov pc, lr
|
|
LEAF_END
|
|
|
|
LEAF_ENTRY InterlockedDecrement16 ; has the same structure as InterlockedIncrement
|
|
1 dcd LDREXH_R12_R0
|
|
sub r12, r12, #1
|
|
dcd STREXH_R3_R12_R0
|
|
cmp r3, #1
|
|
beq %B1
|
|
mov r0, r12
|
|
mov pc, lr
|
|
LEAF_END
|
|
|
|
LEAF_ENTRY InterlockedExchangeAdd ; has the same structure as InterlockedIncrement
|
|
1 ldrex r12, [r0]
|
|
add r2, r12, r1
|
|
strex r3, r2, [r0]
|
|
cmp r3, #1
|
|
beq %B1
|
|
mov r0, r12
|
|
mov pc, lr
|
|
LEAF_END
|
|
|
|
LEAF_ENTRY InterlockedOr ; has the same structure as InterlockedIncrement
|
|
1 ldrex r12, [r0]
|
|
orr r2, r12, r1
|
|
strex r3, r2, [r0]
|
|
cmp r3, #1
|
|
beq %B1
|
|
mov r0, r12
|
|
mov pc, lr
|
|
LEAF_END
|
|
|
|
LEAF_ENTRY InterlockedAnd ; has the same structure as InterlockedIncrement
|
|
1 ldrex r12, [r0]
|
|
and r2, r12, r1
|
|
strex r3, r2, [r0]
|
|
cmp r3, #1
|
|
beq %B1
|
|
mov r0, r12
|
|
mov pc, lr
|
|
LEAF_END
|
|
|
|
LEAF_ENTRY InterlockedXor ; has the same structure as InterlockedIncrement
|
|
1 ldrex r12, [r0]
|
|
eor r2, r12, r1
|
|
strex r3, r2, [r0]
|
|
cmp r3, #1
|
|
beq %B1
|
|
mov r0, r12
|
|
mov pc, lr
|
|
LEAF_END
|
|
|
|
|
|
; InterlockedCompareExchange64 -
|
|
; Arguments:
|
|
; r0 = Pointer to Destination
|
|
; r1 = Exchange.LowPart
|
|
; r2 = Exchange.HighPart
|
|
; r3 = Comperand.LowPart
|
|
; [sp] = Comperand.HighPart
|
|
|
|
NESTED_ENTRY InterlockedCompareExchange64
|
|
stmdb sp!, {r4-r7, lr}
|
|
PROLOG_END
|
|
ldr r12, [sp, #0x14] ; load r12 with Comperand.HighPart
|
|
mov r6, r1 ; move [Exchange.LowPart,Exchange.HighPart] to [r6,r7] because the strex instruction demands that Rm be an even numbered register
|
|
mov r7, r2
|
|
1 dcd LDREXD_R4_R0 ; ldrexd r4, [r0] (r4 = Destination.LowPart, r5 = Destination.HighPart)
|
|
cmp r4, r3 ; if (Destination.LowPart == Comperand.LowPart)
|
|
cmpeq r5, r12 ; && (Destination.HightPart == Comperand.HighPart)
|
|
dcd STREXDEQ_R2_R6_R0 ; streqd r2, r6, [r0] (attempt to store the new value if equal. [r0] = r6; [r0 + 4] = r7;)
|
|
bne %F2 ; if not equal, branch to end and return
|
|
cmp r2, #1 ; check the status of the attempt (0=success, 1=failure)
|
|
beq %B1 ; loop if the store failed
|
|
bne %F3
|
|
2 dcd CLREX ; clrex
|
|
3 mov r0, r4
|
|
mov r1, r5
|
|
ldmia sp!, {r4-r7, pc}
|
|
NESTED_END
|
|
|
|
END
|
|
|