2025-04-27 07:49:33 -04:00

469 lines
14 KiB
ArmAsm
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// TITLE("Interlocked Support")
//++
//
// Copyright (c) 1998 Intel Corporation
// Copyright (c) 1998 Microsoft Corporation
//
// Module Name:
//
// slist.s
//
// Abstract:
//
// This module implements functions to support interlocked S_List
// operations.
//
// Author:
//
// William K. Cheung (v-wcheung) 10-Mar-1998
//
// Environment:
//
// User mode.
//
// Revision History:
//
//--
#include "ksia64.h"
//
// Define how big the depth field. This is the start of the word
//
#define SLIST_DEPTH_BITS_SIZE 16
//
// Define the start of the pointer in an slist
//
#define SLIST_ADR_BITS_START 25
//
// Define the number of alignment bits for an address
//
#define SLIST_ADR_ALIGMENT 4
//
// Define were the sequence bits start and how many there are
//
#define SLIST_SEQ_BITS_START 16
#define SLIST_SEQ_BITS_SIZE 9
//++
//
// PSINGLE_LIST_ENTRY
// RtlpInterlockedFlushSList (
// IN PSLIST_HEADER ListHead
// )
//
// Routine Description:
//
// This function flushes the entire list of entries on a sequenced singly
// linked list so that access to the list is synchronized in a MP system.
// If there are no entries in the list, then a value of NULL is returned.
// Otherwise, the address of the 1st entry on the list is returned as the
// function value.
//
// Arguments:
//
// ListHead (a0) - Supplies a pointer to the sequenced listhead from which
// an current list is to be removed.
//
// Return Value:
//
// The address of the 1st entry on the list, or NULL if the list is
// empty.
//
//--
LEAF_ENTRY(RtlpInterlockedFlushSList)
ALTERNATE_ENTRY(ExpInterlockedFlushSList)
ld8.acq.nt1 t0 = [a0] // load next entry & sequence
#if defined (NTOS_KERNEL_RUNTIME)
add t1 = 8, a0 // Get address of region cell
#endif
;;
#if defined (NTOS_KERNEL_RUNTIME)
ld8 t1 = [t1] // Load region bits
#endif
mov ar.ccv = t0
shr.u v0 = t0, SLIST_ADR_BITS_START
;;
Efls10:
cmp.eq pt1 = v0, r0 // if eq, list is empty
extr.u t5 = t0, SLIST_SEQ_BITS_START, \
SLIST_SEQ_BITS_SIZE // extract the sequence number
(pt1) br.ret.spnt.clr brp // return if the list is null
;;
#if defined (NTOS_KERNEL_RUNTIME)
shladd v0 = v0, SLIST_ADR_ALIGMENT, t1 // merge region & va bits
#else
shl v0 = v0, SLIST_ADR_ALIGMENT // shift address into place
#endif
shl t5 = t5, SLIST_SEQ_BITS_START // shift sequence number into place
;;
cmpxchg8.rel t3 = [a0], t5, ar.ccv // perform the pop
;;
cmp.eq pt1, pt2 = t3, t0 // if eq, cmpxchg8 succeeded
;;
(pt2) mov ar.ccv = t3
(pt1) br.ret.sptk brp
;;
mov t0 = t3
shr.u v0 = t3, SLIST_ADR_BITS_START
br Efls10 // try again
LEAF_EXIT(RtlpInterlockedFlushSList)
SBTTL("Interlocked Pop Entry Sequenced List")
//++
//
// PSINGLE_LIST_ENTRY
// RtlpInterlockedPopEntrySList (
// IN PSLIST_HEADER ListHead
// )
//
// Routine Description:
//
// This function removes an entry from the front of a sequenced singly
// linked list so that access to the list is synchronized in a MP system.
// If there are no entries in the list, then a value of NULL is returned.
// Otherwise, the address of the entry that is removed is returned as the
// function value.
//
// Arguments:
//
// ListHead (a0) - Supplies a pointer to the sequenced listhead from which
// an entry is to be removed.
//
// Return Value:
//
// The address of the entry removed from the list, or NULL if the list is
// empty.
//
//--
LEAF_ENTRY(RtlpInterlockedPopEntrySList)
ALTERNATE_ENTRY(ExpInterlockedPopEntrySList)
ALTERNATE_ENTRY(ExpInterlockedPopEntrySListResume)
ld8.acq.nt1 t0 = [a0] // load next entry & sequence
#if defined (NTOS_KERNEL_RUNTIME)
add t1 = 8, a0 // Generate address region bits
#endif
;;
Epop10:
#if defined (NTOS_KERNEL_RUNTIME)
ld8 t1 = [t1] // capture region bits
#endif
mov ar.ccv = t0
shr.u t2 = t0, SLIST_ADR_BITS_START
;;
#if defined (NTOS_KERNEL_RUNTIME)
shladd v0 = t2, SLIST_ADR_ALIGMENT, t1 // merge region & va bits
#else
shl v0 = t2, SLIST_ADR_ALIGMENT // shift va into place
#endif
;;
#if defined (NTOS_KERNEL_RUNTIME)
cmp.eq pt2, pt1 = t1, v0 // if eq, list is empty
#else
cmp.eq pt2, pt1 = r0, v0 // if eq, list is empty
#endif
sub t4 = t0, zero, 1 // adjust depth
;;
//
// N.B. It is possible for the following instruction to fault in the rare
// case where the first entry in the list is allocated on another
// processor and free between the time the free pointer is read above
// and the following instruction. When this happens, the access fault
// code continues execution by skipping the following instruction slot.
// This results in the compare failing and the entire operation is
// retried.
//
ALTERNATE_ENTRY(ExpInterlockedPopEntrySListFault)
(pt1) ld8.acq t5 = [v0] // get addr of successor entry
extr.u t4 = t4, 0, SLIST_DEPTH_BITS_SIZE + \
SLIST_SEQ_BITS_SIZE // extract depth & sequence
;;
(pt1) shl t5 = t5, SLIST_ADR_BITS_START - \
SLIST_ADR_ALIGMENT // shift va into position dropping alignment bits
(pt2) add v0 = 0, zero // The list is empty clear retur value
;;
(pt1) ld8.nt1 t3 = [a0] // reload next entry & sequence
(pt1) or t5 = t4, t5 // merge va, depth & sequence
(pt2) br.ret.spnt.clr brp // return if the list is null
;;
cmp.eq.unc pt4, pt1 = t3, t0
;;
ALTERNATE_ENTRY(ExpInterlockedPopEntrySListEnd)
(pt4) cmpxchg8.rel t3 = [a0], t5, ar.ccv // perform the pop
nop.i 0
;;
(pt4) cmp.eq.unc pt3 = t3, t0 // if eq, cmpxchg8 succeeded
#if defined (NTOS_KERNEL_RUNTIME)
add t1 = 8, a0
#endif
mov t0 = t3
(pt3) br.ret.sptk brp
br Epop10 // try again
LEAF_EXIT(RtlpInterlockedPopEntrySList)
//++
//
// PSINGLE_LIST_ENTRY
// RtlpInterlockedPushEntrySList (
// IN PSLIST_HEADER ListHead,
// IN PSINGLE_LIST_ENTRY ListEntry
// )
//
// Routine Description:
//
// This function inserts an entry at the head of a sequenced singly linked
// list so that access to the list is synchronized in an MP system.
//
// Arguments:
//
// ListHead (a0) - Supplies a pointer to the sequenced listhead into which
// an entry is to be inserted.
//
// ListEntry (a1) - Supplies a pointer to the entry to be inserted at the
// head of the list.
//
// Return Value:
//
// Previous contents of ListHead. NULL implies list went from empty
// to not empty.
//
//--
LEAF_ENTRY(RtlpInterlockedPushEntrySList)
ALTERNATE_ENTRY(ExpInterlockedPushEntrySList)
ld8.acq.nt1 t0 = [a0] // load next entry & sequence
mov t6 = (1<<SLIST_SEQ_BITS_START)+1 // Increment sequence and depth
ldf.fill ft0 = [a1] // Force alignment check.
shl t5 = a1, SLIST_ADR_BITS_START - \
SLIST_ADR_ALIGMENT // shift va into position
;;
#if DBG==1
and t3 = (1<<SLIST_ADR_ALIGMENT)-1, a1
add t2 = 8, a0
dep t1 = 0, a1, 0, 61 // capture region bits
;;
cmp.eq pt2, pt1 = t3, r0
#if defined (NTOS_KERNEL_RUNTIME)
ld8 t2 = [t2]
;;
(pt2) cmp.eq pt2, pt1 = t2, t1
#endif
;;
(pt1) break.i 0x80016
#endif
Epush10:
mov ar.ccv = t0 // set the comparand
add t4 = t0, t6
shr.u v0 = t0, SLIST_ADR_BITS_START
;;
#if defined (NTOS_KERNEL_RUNTIME)
dep t1 = 0, a1, 0, 61 // capture region bits
#endif
cmp.ne pt3 = zero, v0 // if ne, list not empty
;;
#if defined (NTOS_KERNEL_RUNTIME)
(pt3) shladd v0 = v0, SLIST_ADR_ALIGMENT, t1 // merge region & va bits
#else
(pt3) shl v0 = v0, SLIST_ADR_ALIGMENT // shift address into place
#endif
extr.u t4 = t4, 0, SLIST_DEPTH_BITS_SIZE + \
SLIST_SEQ_BITS_SIZE // extract depth & sequence
;;
st8 [a1] = v0
or t5 = t4, t5 // merge va, depth & sequence
;;
cmpxchg8.rel t3 = [a0], t5, ar.ccv
;;
cmp.eq pt2, pt1 = t0, t3
dep t5 = 0, t5, 0, SLIST_DEPTH_BITS_SIZE + \
SLIST_SEQ_BITS_SIZE // Zero depth a sequence
;;
(pt2) br.ret.sptk brp // if equal, return
(pt1) mov t0 = t3
(pt1) br.spnt Epush10 // retry
;;
LEAF_EXIT(RtlpInterlockedPushEntrySList)
//++
//
// SINGLE_LIST_ENTRY
// FASTCALL
// InterlockedPushListSList (
// IN PSLIST_HEADER ListHead,
// IN PSINGLE_LIST_ENTRY List,
// IN PSINGLE_LIST_ENTRY ListEnd,
// IN ULONG Count
// )
//
// Routine Description:
//
// This function will push multiple entries onto an SList at once
//
// Arguments:
//
// ListHead - List head to push the list to.
//
// List - The list to add to the front of the SList
// ListEnd - The last element in the chain
// Count - The number of items in the chain
//
// Return Value:
//
// PSINGLE_LIST_ENTRY - The old header pointer is returned
//
//--
LEAF_ENTRY(InterlockedPushListSList)
ld8.acq.nt1 t0 = [a0] // load next entry & sequence
mov t6 = 0x10000 // Generate literal for adjusting depth and count
ldf.fill ft0 = [a1] // Force alignment check.
shl t5 = a1, SLIST_ADR_BITS_START - \
SLIST_ADR_ALIGMENT // shift va into position
;;
#if DBG==1
and t3 = (1<<SLIST_ADR_ALIGMENT)-1, a1
add t2 = 8, a0
dep t1 = 0, a1, 0, 61 // capture region bits
;;
cmp.eq pt2, pt1 = t3, r0
#if defined (NTOS_KERNEL_RUNTIME)
ld8 t2 = [t2]
;;
(pt2) cmp.eq pt2, pt1 = t2, t1
#endif
;;
(pt1) break.i 0x80016
#endif
Epushl10:
mov ar.ccv = t0 // set the comparand
add t4 = t0, t6
shr.u v0 = t0, SLIST_ADR_BITS_START
;;
#if defined (NTOS_KERNEL_RUNTIME)
dep t1 = 0, a1, 0, 61 // capture region bits
#endif
cmp.ne pt3 = zero, v0 // if ne, list not empty
add t4 = t4, a3 // Add in count
;;
#if defined (NTOS_KERNEL_RUNTIME)
(pt3) shladd v0 = v0, SLIST_ADR_ALIGMENT, t1 // merge region & va bits
#else
(pt3) shl v0 = v0, SLIST_ADR_ALIGMENT // shift address into place
#endif
extr.u t4 = t4, 0, SLIST_DEPTH_BITS_SIZE + \
SLIST_SEQ_BITS_SIZE // extract depth & sequence
;;
st8 [a2] = v0
or t5 = t4, t5 // merge va, depth & sequence
;;
cmpxchg8.rel t3 = [a0], t5, ar.ccv
;;
cmp.eq pt2, pt1 = t0, t3
dep t5 = 0, t5, 0, SLIST_DEPTH_BITS_SIZE + \
SLIST_SEQ_BITS_SIZE // zero depth and sequence
mov t0 = t3
(pt2) br.ret.sptk brp // if equal, return
(pt1) br.spnt Epushl10 // retry
;;
LEAF_EXIT(InterlockedPushListSList)
//++
//
// PSINGLE_LIST_ENTRY
// FirstEntrySList (
// IN PSLIST_HEADER SListHead
// )
//
// Routine Description:
//
// This function returns the address of the fisrt entry in the SLIST or
// NULL.
//
// Arguments:
//
// ListHead - Supplies a pointer to the sequenced listhead from
// which the first entry address is to be computed.
//
// Return Value:
//
// The address of the first entry is the specified, or NULL if the list is
// empty.
//
//--
LEAF_ENTRY(FirstEntrySList)
ld8 t0 = [a0] // load next entry & sequence
#if defined (NTOS_KERNEL_RUNTIME)
add t1 = 8, a0 // Generate address region bits
#endif
;;
#if defined (NTOS_KERNEL_RUNTIME)
ld8 t1 = [t1] // capture region bits
#endif
shr.u t2 = t0, SLIST_ADR_BITS_START
;;
#if defined (NTOS_KERNEL_RUNTIME)
cmp.eq pt0 = t2, r0
shladd v0 = t2, SLIST_ADR_ALIGMENT, t1 // merge region & va bits
#else
shl v0 = t2, SLIST_ADR_ALIGMENT // shift va into place
#endif
;;
#if defined (NTOS_KERNEL_RUNTIME)
(pt0) mov v0 = r0
#endif
br.ret.sptk brp // return function value
LEAF_EXIT(FirstEntrySList)