214 lines
6.1 KiB
NASM
214 lines
6.1 KiB
NASM
title "Interlocked Support"
|
|
;++
|
|
;
|
|
; Copyright (c) 1989 Microsoft Corporation
|
|
;
|
|
; Module Name:
|
|
;
|
|
; intrlock.asm
|
|
;
|
|
; Abstract:
|
|
;
|
|
; This module implements functions to support interlocked operations.
|
|
; Interlocked operations can only operate on nonpaged data.
|
|
;
|
|
; Author:
|
|
;
|
|
; Shie-Lin Tzong (shielint) 12-Feb-1990
|
|
;
|
|
; Environment:
|
|
;
|
|
; Any mode.
|
|
;
|
|
; Revision History:
|
|
;
|
|
; bryanwi 1-aug-90 Clean up and fix stuff.
|
|
; bryanwi 3-aug-90 Add ExInterlockedIncrementLlong,...
|
|
;
|
|
;--
|
|
.386p
|
|
.xlist
|
|
include ks386.inc
|
|
include callconv.inc ; calling convention macros
|
|
.list
|
|
|
|
|
|
_TEXT SEGMENT DWORD PUBLIC 'CODE'
|
|
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
|
|
|
|
;++
|
|
;
|
|
; General Notes on Interlocked Procedures:
|
|
;
|
|
; These procedures assume that neither their code, nor any of
|
|
; the data they touch, will cause a page fault.
|
|
;
|
|
; They use spinlocks to achieve MP atomicity, iff it's an MP machine.
|
|
; (The spinlock macros generate zilch if NT_UP = 1, and
|
|
; we if out some aux code here as well.)
|
|
;
|
|
; They turn off interrupts so that they can be used for synchronization
|
|
; between ISRs and driver code. Flags are preserved so they can
|
|
; be called in special code (Like IPC interrupt handlers) that
|
|
; may have interrupts off.
|
|
;
|
|
;--
|
|
|
|
|
|
;; align 512
|
|
|
|
page ,132
|
|
subttl "ExInterlockedAddLargeInteger"
|
|
;++
|
|
;
|
|
; LARGE_INTEGER
|
|
; ExInterlockedAddLargeInteger (
|
|
; IN PLARGE_INTEGER Addend,
|
|
; IN LARGE_INTEGER Increment,
|
|
; IN PKSPIN_LOCK Lock
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This function performs an interlocked add of an increment value to an
|
|
; addend variable of type unsigned large integer. The initial value of
|
|
; the addend variable is returned as the function value.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; (TOS+4) = Addend - a pointer to the addend value
|
|
; (TOS+8) = Increment - the increment value
|
|
; (TOS+16) = Lock - a pointer to a pointer to a spin lock
|
|
;
|
|
; Return Value:
|
|
;
|
|
; The initial value of the addend variable is stored in eax:edx
|
|
;
|
|
;--
|
|
|
|
EiulAddend equ [ebp + 8]
|
|
EiulIncrement equ [ebp + 12]
|
|
EiulLock equ [ebp + 20]
|
|
EiulRetval equ [ebp - 8]
|
|
|
|
cPublicProc _ExInterlockedAddLargeInteger, 4
|
|
|
|
push ebp
|
|
mov ebp,esp
|
|
sub esp, 8
|
|
|
|
eiul10: pushfd
|
|
cli ; disable interrupts
|
|
|
|
mov eax,EiulAddend ; (eax)-> addend variable
|
|
mov ecx,[eax] ; (ecx)= low part of addend value
|
|
mov edx,[eax]+4 ; (edx)= high part of addend value
|
|
mov EiulRetVal,ecx ; set low part of return value
|
|
mov EiulRetVal+4,edx ; set high part of return value
|
|
add ecx,EiulIncrement ; add low parts of large integer
|
|
adc edx,EiulIncrement+4 ; add high parts of large integer and carry
|
|
mov eax,EiulAddend ; RELOAD (eax)-> addend variable
|
|
mov [eax],ecx ; store low part of result
|
|
mov [eax]+4,edx ; store high part of result
|
|
|
|
popfd ; restore flags including interrupts
|
|
mov eax, EiulRetval ; calling convention
|
|
mov edx, EiulRetval+4 ; calling convention
|
|
mov esp, ebp
|
|
pop ebp
|
|
stdRET _ExInterlockedAddLargeInteger
|
|
|
|
stdENDP _ExInterlockedAddLargeInteger
|
|
|
|
page ,132
|
|
subttl "ExInterlocked Exchange Add Large Integer"
|
|
;++
|
|
;
|
|
; LARGE_INTEGER
|
|
; ExInterlockedExchangeAddLargeInteger (
|
|
; IN PLARGE_INTEGER Addend,
|
|
; IN LARGE_INTEGER Increment,
|
|
; IN PKSPIN_LOCK Lock
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This function performs an interlocked add of an increment value to an
|
|
; addend variable of type unsigned large integer. The initial value of
|
|
; the addend variable is returned as the function value.
|
|
;
|
|
; N.B. The cmpxchg8b instruction is only supported on some processors.
|
|
; If the host processor does not support this instruction, then
|
|
; then following code is patched to contain a jump to the normal
|
|
; add large integer code which has a compatible calling sequence
|
|
; and data structure.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; (TOS + 4) = Addend - Supplies a pointer to the addend variable.
|
|
;
|
|
; (TOS + 8) = Increment - Supplies the increment value.
|
|
;
|
|
; (TOS + 16) = Lock - Supplies a pointer a spin lock.
|
|
;
|
|
; N.B. This routine does not use the spin lock.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; The initial value of the addend variable is stored in eax:edx.
|
|
;
|
|
;--
|
|
|
|
XaAddend equ [esp + 12]
|
|
XaIncrement equ [esp + 16]
|
|
XaLock equ [esp + 24]
|
|
|
|
cPublicProc _ExInterlockedExchangeAddLargeInteger, 4
|
|
|
|
cPublicFpo 0,2
|
|
|
|
;
|
|
; Save nonvolatile registers and get the addend value.
|
|
;
|
|
|
|
push ebx ; save nonvolatile registers
|
|
push ebp ;
|
|
mov ebp, XaAddend ; get the addend variable address
|
|
mov eax,[ebp] + 0 ; get low part of addend value
|
|
mov edx,[ebp] + 4 ; get high part of addend value
|
|
|
|
;
|
|
; Add the increment value to the addend value.
|
|
;
|
|
|
|
Xa10: mov ebx, eax ; copy low part of addend value
|
|
mov ecx, edx ; copy high part of addend value
|
|
add ebx, XaIncrement ; add low part of increment value
|
|
adc ecx, XaIncrement + 4 ; add high part of increment value
|
|
|
|
;
|
|
; Exchange the updated addend value with the previous addend value.
|
|
;
|
|
|
|
.586
|
|
cmpxchg8b qword ptr [ebp] ; compare and exchange
|
|
.386
|
|
|
|
jnz short Xa10 ; if z clear, exchange failed
|
|
|
|
;
|
|
; Restore nonvolatile registers and return result.
|
|
;
|
|
|
|
cPublicFpo 0,0
|
|
|
|
pop ebp ;
|
|
pop ebx ;
|
|
|
|
stdRET _ExInterlockedExchangeAddLargeInteger
|
|
|
|
stdENDP _ExInterlockedExchangeAddLargeInteger
|
|
|
|
_TEXT ends
|
|
end
|