x4intrlk.s
Upload User: caisha3
Upload Date: 2013-09-21
Package Size: 208739k
Code Size: 31k
Category:

Windows Develop

Development Platform:

Visual C++

  1. //       TITLE("Interlocked Support")
  2. //++
  3. //
  4. // Copyright (c) 1990  Microsoft Corporation
  5. //
  6. // Module Name:
  7. //
  8. //    intrlock.s
  9. //
  10. // Abstract:
  11. //
  12. //    This module implements functions to support interlocked operations.
  13. //    Interlocked operations can only operate on nonpaged data and the
  14. //    specified spinlock cannot be used for any other purpose.
  15. //
  16. // Author:
  17. //
  18. //    David N. Cutler (davec) 26-Mar-1990
  19. //
  20. // Environment:
  21. //
  22. //    Kernel mode.
  23. //
  24. // Revision History:
  25. //
  26. //--
  27. #include "ksmips.h"
  28.         SBTTL("Interlocked Add Large Integer")
  29. //++
  30. //
  31. // LARGE_INTEGER
  32. // ExInterlockedAddLargeInteger (
  33. //    IN PLARGE_INTEGER Addend,
  34. //    IN LARGE_INTEGER Increment,
  35. //    IN PKSPIN_LOCK Lock
  36. //    )
  37. //
  38. // Routine Description:
  39. //
  40. //    This function performs an interlocked add of an increment value to an
  41. //    addend variable of type large integer. The initial value of the addend
  42. //    variable is returned as the function value.
  43. //
  44. // Arguments:
  45. //
  46. //    Addend (a1) - Supplies a pointer to a variable whose value is to be
  47. //       adjusted by the increment value.
  48. //
  49. //    Increment (a2, a3) - Supplies the increment value to be added to the
  50. //       addend variable.
  51. //
  52. //    Lock (4 * 4(sp)) - Supplies a pointer to a spin lock to be used to
  53. //       synchronize access to the addend variable.
  54. //
  55. // Return Value:
  56. //
  57. //    The initial value of the addend variable is stored at the address
  58. //    supplied by a0.
  59. //
  60. // Implementation Note:
  61. //
  62. //    The arithmetic for this function is performed as if this were an
  63. //    unsigned large integer since this routine may not incur an overflow
  64. //    exception.
  65. //
  66. //--
  67.         LEAF_ENTRY(ExInterlockedAddLargeInteger)
  68.         lw      t0,4 * 4(sp)            // get address of spin lock
  69. 5:      DISABLE_INTERRUPTS(t1)          // disable interrupts
  70. #if !defined(NT_UP)
  71. 10:     ll      t2,0(t0)                // get current lock value
  72.         move    t3,t0                   // set ownership value
  73.         bne     zero,t2,20f             // if ne, spin lock owned
  74.         sc      t3,0(t0)                // set spin lock owned
  75.         beq     zero,t3,10b             // if eq, store conditional failed
  76. #endif
  77.         lw      t2,0(a1)                // get low part of addend value
  78.         lw      t3,4(a1)                // get high part of addend value
  79.         addu    a2,t2,a2                // add low parts of large integer
  80.         addu    a3,t3,a3                // add high parts of large integer
  81.         sltu    t4,a2,t2                // generate carry from low part
  82.         addu    a3,a3,t4                // add carry to high part
  83.         sw      a2,0(a1)                // store low part of result
  84.         sw      a3,4(a1)                // store high part of result
  85. #if !defined(NT_UP)
  86.         sw      zero,0(t0)              // set spin lock not owned
  87. #endif
  88.         ENABLE_INTERRUPTS(t1)           // enable interrupts
  89.         sw      t2,0(a0)                // set low part of initial value
  90.         sw      t3,4(a0)                // set high part of initial value
  91.         move    v0,a0                   // set function return register
  92.         j       ra                      // return
  93. #if !defined(NT_UP)
  94. 20:     ENABLE_INTERRUPTS(t1)           // enable interrupts
  95.         b       5b                      // try again
  96. #endif
  97.         .end    ExInterlockedAddLargeInteger
  98.         SBTTL("Interlocked Add Large Statistic")
  99. //++
  100. //
  101. // VOID
  102. // ExInterlockedAddLargeStatistic (
  103. //    IN PLARGE_INTEGER Addend,
  104. //    IN ULONG Increment
  105. //    )
  106. //
  107. // Routine Description:
  108. //
  109. //    This function performs an interlocked add of an increment value to an
  110. //    addend variable of type large integer.
  111. //
  112. // Arguments:
  113. //
  114. //    Addend (a0) - Supplies a pointer to a variable whose value is to be
  115. //       adjusted by the increment value.
  116. //
  117. //    Increment (a1) - Supplies the increment value to be added to the
  118. //       addend variable.
  119. //
  120. // Return Value:
  121. //
  122. //    None.
  123. //
  124. // Implementation Note:
  125. //
  126. //    The arithmetic for this function is performed as if this were an
  127. //    unsigned large integer since this routine may not incur an overflow
  128. //    exception.
  129. //
  130. //--
  131.         LEAF_ENTRY(ExInterlockedAddLargeStatistic)
  132. 10:     lld     t0,0(a0)                // get large statistic value
  133.         daddu   t0,t0,a1                // add increment
  134.         scd     t0,0(a0)                // store large statistic value
  135.         beq     zero,t0,10b             // if eq, store conditional failed
  136.         j       ra                      //
  137.         .end    ExInterlockedAddLargeStatistic
  138.         SBTTL("Interlocked Add Unsigned Long")
  139. //++
  140. //
  141. // ULONG
  142. // ExInterlockedAddUlong (
  143. //    IN PULONG Addend,
  144. //    IN ULONG Increment,
  145. //    IN PKSPIN_LOCK Lock
  146. //    )
  147. //
  148. // Routine Description:
  149. //
  150. //    This function performs an interlocked add of an increment value to an
  151. //    addend variable of type unsigned long. The initial value of the addend
  152. //    variable is returned as the function value.
  153. //
  154. // Arguments:
  155. //
  156. //    Addend (a0) - Supplies a pointer to a variable whose value is to be
  157. //       adjusted by the increment value.
  158. //
  159. //    Increment (a1) - Supplies the increment value to be added to the
  160. //       addend variable.
  161. //
  162. //    Lock (a2) - Supplies a pointer to a spin lock to be used to synchronize
  163. //       access to the addend variable.
  164. //
  165. // Return Value:
  166. //
  167. //    The initial value of the addend variable.
  168. //
  169. //--
  170.         LEAF_ENTRY(ExInterlockedAddUlong)
  171. 5:      DISABLE_INTERRUPTS(t0)          // disable interrupts
  172. #if !defined(NT_UP)
  173. 10:     ll      t1,0(a2)                // get current lock value
  174.         move    t2,a2                   // set ownership value
  175.         bne     zero,t1,20f             // if ne, spin lock owned
  176.         sc      t2,0(a2)                // set spin lock owned
  177.         beq     zero,t2,10b             // if eq, store conditional failed
  178. #endif
  179.         lw      v0,0(a0)                // get initial addend value
  180.         addu    t1,v0,a1                // compute adjusted value
  181.         sw      t1,0(a0)                // set updated addend value
  182. #if !defined(NT_UP)
  183.         sw      zero,0(a2)              // set spin lock not owned
  184. #endif
  185.         ENABLE_INTERRUPTS(t0)           // enable interrupts
  186.         j       ra                      // return
  187. #if !defined(NT_UP)
  188. 20:     ENABLE_INTERRUPTS(t0)           // enable interrupts
  189.         b       5b                      // try again
  190. #endif
  191.         .end    ExInterlockedAddUlong
  192.         SBTTL("Interlocked Exchange Unsigned Long")
  193. //++
  194. //
  195. // ULONG
  196. // ExInterlockedExchangeUlong (
  197. //    IN PULONG Source,
  198. //    IN ULONG Value,
  199. //    IN PKSPIN_LOCK Lock
  200. //    )
  201. //
  202. // Routine Description:
  203. //
  204. //    This function performs an interlocked exchange of a longword value with
  205. //    a longword in memory and returns the memory value.
  206. //
  207. //    N.B. There is an alternate entry point provided for this routine which
  208. //         is MIPS target specific and whose prototype does not include the
  209. //         spinlock parameter. Since the routine never refers to the spinlock
  210. //         parameter, no additional code is required.
  211. //
  212. // Arguments:
  213. //
  214. //    Source (a0) - Supplies a pointer to a variable whose value is to be
  215. //       exchanged.
  216. //
  217. //    Value (a1) - Supplies the value to exchange with the source value.
  218. //
  219. //    Lock (a2) - Supplies a pointer to a spin lock to be used to synchronize
  220. //       access to the source variable.
  221. //
  222. // Return Value:
  223. //
  224. //    The source value is returned as the function value.
  225. //
  226. //--
  227.         LEAF_ENTRY(ExInterlockedExchangeUlong)
  228.         ALTERNATE_ENTRY(ExMipsInterlockedExchangeUlong)
  229. 10:     ll      v0,0(a0)                // get current source value
  230.         move    t1,a1                   // set exchange value
  231.         sc      t1,0(a0)                // set new source value
  232.         beq     zero,t1,10b             // if eq, store conditional failed
  233.         j       ra                      // return
  234.         .end    ExInterlockedExchangeUlong
  235.         SBTTL("Interlocked Exchange Add Large Integer")
  236. //++
  237. //
  238. // LARGE_INTEGER
  239. // ExpInterlockedExchangeAddLargeInteger (
  240. //    IN PLARGE_INTEGER Addend,
  241. //    IN LARGE_INTEGER Increment,
  242. //    IN PKSPIN_LOCK Lock
  243. //    )
  244. //
  245. // Routine Description:
  246. //
  247. //    This function performs an interlocked add of an increment value to an
  248. //    addend variable of type large integer. The initial value of the addend
  249. //    variable is returned as the function value.
  250. //
  251. // Arguments:
  252. //
  253. //    Addend (a1) - Supplies a pointer to a variable whose value is to be
  254. //       adjusted by the increment value.
  255. //
  256. //    Increment (a2, a3) - Supplies the increment value to be added to the
  257. //       addend variable.
  258. //
  259. // Return Value:
  260. //
  261. //    The initial value of the addend variable is stored at the address
  262. //    supplied by a0.
  263. //
  264. // Implementation Note:
  265. //
  266. //    The arithmetic for this function is performed as if this were an
  267. //    unsigned large integer since this routine may not incur an overflow
  268. //    exception.
  269. //
  270. //--
  271.         LEAF_ENTRY(ExpInterlockedExchangeAddLargeInteger)
  272.         dsll    a2,a2,32                // merge low and high parts of
  273.         dsrl    a2,a2,32                // increment value
  274.         dsll    a3,a3,32                //
  275.         or      a2,a2,a3                //
  276. 10:     lld     a3,0(a1)                // get addend value
  277.         daddu   v0,a3,a2                // add increment
  278.         scd     v0,0(a1)                // store addend value
  279.         beq     zero,v0,10b             // if eq, store conditional failed
  280.         sd      a3,0(a0)                //
  281.         move    v0,a0                   // set function return register
  282.         j       ra                      // return
  283.         .end    ExpInterlockedExchangeAddLargeInteger
  284.         SBTTL("Interlocked Decrement Long")
  285. //++
  286. //
  287. // INTERLOCKED_RESULT
  288. // ExInterlockedDecrementLong (
  289. //    IN PLONG Addend,
  290. //    IN PKSPIN_LOCK Lock
  291. //    )
  292. //
  293. // Routine Description:
  294. //
  295. //    This function performs an interlocked decrement on an addend variable
  296. //    of type signed long. The sign and whether the result is zero is returned
  297. //    as the function value.
  298. //
  299. //    N.B. There is an alternate entry point provided for this routine which
  300. //         is MIPS target specific and whose prototype does not include the
  301. //         spinlock parameter. Since the routine never refers to the spinlock
  302. //         parameter, no additional code is required.
  303. //
  304. // Arguments:
  305. //
  306. //    Addend (a0) - Supplies a pointer to a variable whose value is to be
  307. //       decremented.
  308. //
  309. //    Lock (a1) - Supplies a pointer to a spin lock to be used to synchronize
  310. //       access to the addend variable.
  311. //
  312. // Return Value:
  313. //
  314. //    RESULT_NEGATIVE is returned if the resultant addend value is negative.
  315. //    RESULT_ZERO is returned if the resultant addend value is zero.
  316. //    RESULT_POSITIVE is returned if the resultant addend value is positive.
  317. //
  318. //--
  319.         LEAF_ENTRY(ExInterlockedDecrementLong)
  320.         ALTERNATE_ENTRY(ExMipsInterlockedDecrementLong)
  321. 10:     ll      t1,0(a0)                // get current addend value
  322.         subu    t2,t1,1                 // decrement addend value
  323.         sc      t2,0(a0)                // set new addend value
  324.         beq     zero,t2,10b             // if eq, store conditional failed
  325.         subu    v0,t1,1                 // decrement addend value
  326.         sltu    t0,zero,v0              // check if result is nonzero
  327.         sra     v0,v0,31                // sign extend result value
  328.         subu    v0,v0,t0                // compute negative, zero, or positive
  329.         j       ra                      // return
  330.         .end    ExInterlockedDecrementLong
  331.         SBTTL("Interlocked Increment Long")
  332. //++
  333. //
  334. // INTERLOCKED_RESULT
  335. // ExInterlockedIncrementLong (
  336. //    IN PLONG Addend,
  337. //    IN PKSPIN_LOCK Lock
  338. //    )
  339. //
  340. // Routine Description:
  341. //
  342. //    This function performs an interlocked increment on an addend variable
  343. //    of type signed long. The sign and whether the result is zero is returned
  344. //    as the function value.
  345. //
  346. //    N.B. There is an alternate entry point provided for this routine which
  347. //         is MIPS target specific and whose prototype does not include the
  348. //         spinlock parameter. Since the routine never refers to the spinlock
  349. //         parameter, no additional code is required.
  350. //
  351. // Arguments:
  352. //
  353. //    Addend (a0) - Supplies a pointer to a variable whose value is to be
  354. //       incremented.
  355. //
  356. //    Lock (a1) - Supplies a pointer to a spin lock to be used to synchronize
  357. //       access to the addend variable.
  358. //
  359. // Return Value:
  360. //
  361. //    RESULT_NEGATIVE is returned if the resultant addend value is negative.
  362. //    RESULT_ZERO is returned if the resultant addend value is zero.
  363. //    RESULT_POSITIVE is returned if the resultant addend value is positive.
  364. //
  365. //--
  366.         LEAF_ENTRY(ExInterlockedIncrementLong)
  367.         ALTERNATE_ENTRY(ExMipsInterlockedIncrementLong)
  368. 10:     ll      t1,0(a0)                // get current addend value
  369.         addu    t2,t1,1                 // increment addend value
  370.         sc      t2,0(a0)                // set new addend value
  371.         beq     zero,t2,10b             // if eq, store conditional failed
  372.         addu    v0,t1,1                 // increment addend value
  373.         sltu    t0,zero,v0              // check if result is nonzero
  374.         sra     v0,v0,31                // sign extend result value
  375.         subu    v0,v0,t0                // compute negative, zero, or positive
  376.         j       ra                      // return
  377.         .end    ExInterlockedIncrementLong
  378.         SBTTL("Interlocked Insert Head List")
  379. //++
  380. //
  381. // PLIST_ENTRY
  382. // ExInterlockedInsertHeadList (
  383. //    IN PLIST_ENTRY ListHead,
  384. //    IN PLIST_ENTRY ListEntry,
  385. //    IN PKSPIN_LOCK Lock
  386. //    )
  387. //
  388. // Routine Description:
  389. //
  390. //    This function inserts an entry at the head of a doubly linked list
  391. //    so that access to the list is synchronized in a multiprocessor system.
  392. //
  393. // Arguments:
  394. //
  395. //    ListHead (a0) - Supplies a pointer to the head of the doubly linked
  396. //       list into which an entry is to be inserted.
  397. //
  398. //    ListEntry (a1) - Supplies a pointer to the entry to be inserted at the
  399. //       head of the list.
  400. //
  401. //    Lock (a2) - Supplies a pointer to a spin lock to be used to synchronize
  402. //       access to the list.
  403. //
  404. // Return Value:
  405. //
  406. //    Pointer to entry that was at the head of the list or NULL if the list
  407. //    was empty.
  408. //
  409. //--
  410.         LEAF_ENTRY(ExInterlockedInsertHeadList)
  411. 5:      DISABLE_INTERRUPTS(t0)          // disable interrupts
  412. #if !defined(NT_UP)
  413. 10:     ll      t2,0(a2)                // get current lock value
  414.         move    t3,a2                   // set ownership value
  415.         bne     zero,t2,20f             // if ne, spin lock owned
  416.         sc      t3,0(a2)                // set spin lock owned
  417.         beq     zero,t3,10b             // if eq, store conditional failed
  418. #endif
  419.         lw      t2,LsFlink(a0)          // get address of next entry
  420.         sw      t2,LsFlink(a1)          // store next link in entry
  421.         sw      a0,LsBlink(a1)          // store previous link in entry
  422.         sw      a1,LsBlink(t2)          // store previous link in next
  423.         sw      a1,LsFlink(a0)          // store next link in head
  424.         xor     v0,t2,a0                // check if list was empty
  425.         beq     v0,zero,15f             // if eq, list was null
  426.         move    v0,t2                   // return previous entry at head
  427. 15:
  428. #if !defined(NT_UP)
  429.         sw      zero,0(a2)              // set spin lock not owned
  430. #endif
  431.         ENABLE_INTERRUPTS(t0)           // enable interrupts
  432.         j       ra                      // return
  433. #if !defined(NT_UP)
  434. 20:     ENABLE_INTERRUPTS(t0)           // enable interrupts
  435.         b       5b                      // try again
  436. #endif
  437.         .end    ExInterlockedInsertHeadList
  438.         SBTTL("Interlocked Insert Tail List")
  439. //++
  440. //
  441. // PLIST_ENTRY
  442. // ExInterlockedInsertTailList (
  443. //    IN PLIST_ENTRY ListHead,
  444. //    IN PLIST_ENTRY ListEntry,
  445. //    IN PKSPIN_LOCK Lock
  446. //    )
  447. //
  448. // Routine Description:
  449. //
  450. //    This function inserts an entry at the tail of a doubly linked list
  451. //    so that access to the list is synchronized in a multiprocessor system.
  452. //
  453. // Arguments:
  454. //
  455. //    ListHead (a0) - Supplies a pointer to the head of the doubly linked
  456. //       list into which an entry is to be inserted.
  457. //
  458. //    ListEntry (a1) - Supplies a pointer to the entry to be inserted at the
  459. //       tail of the list.
  460. //
  461. //    Lock (a2) - Supplies a pointer to a spin lock to be used to synchronize
  462. //       access to the list.
  463. //
  464. // Return Value:
  465. //
  466. //    Pointer to entry that was at the tail of the list or NULL if the list
  467. //    was empty.
  468. //
  469. //--
  470.         LEAF_ENTRY(ExInterlockedInsertTailList)
  471. 5:      DISABLE_INTERRUPTS(t0)          // disable interrupts
  472. #if !defined(NT_UP)
  473. 10:     ll      t2,0(a2)                // get current lock value
  474.         move    t3,a2                   // set ownership value
  475.         bne     zero,t2,20f             // if ne, spin lock owned
  476.         sc      t3,0(a2)                // set spin lock owned
  477.         beq     zero,t3,10b             // if eq, store conditional failed
  478. #endif
  479.         lw      t2,LsBlink(a0)          // get address of previous entry
  480.         sw      a0,LsFlink(a1)          // store next link in entry
  481.         sw      t2,LsBlink(a1)          // store previous link in entry
  482.         sw      a1,LsBlink(a0)          // store previous link in next
  483.         sw      a1,LsFlink(t2)          // store next link in head
  484.         xor     v0,t2,a0                // check is list was emptyr
  485.         beq     v0,zero,15f             // if eq, list was empty
  486.         move    v0,t2                   // return previous entry at tail
  487. 15:
  488. #if !defined(NT_UP)
  489.         sw      zero,0(a2)              // set spin lock not owned
  490. #endif
  491.         ENABLE_INTERRUPTS(t0)           // enable interrupts
  492.         j       ra                      // return
  493. #if !defined(NT_UP)
  494. 20:     ENABLE_INTERRUPTS(t0)           // enable interrupts
  495.         b       5b                      // try again
  496. #endif
  497.         .end    ExInterlockedInsertTailList
  498.         SBTTL("Interlocked Remove Head List")
  499. //++
  500. //
  501. // PLIST_ENTRY
  502. // ExInterlockedRemoveHeadList (
  503. //    IN PLIST_ENTRY ListHead,
  504. //    IN PKSPIN_LOCK Lock
  505. //    )
  506. //
  507. // Routine Description:
  508. //
  509. //    This function removes an entry from the head of a doubly linked list
  510. //    so that access to the list is synchronized in a multiprocessor system.
  511. //    If there are no entries in the list, then a value of NULL is returned.
  512. //    Otherwise, the address of the entry that is removed is returned as the
  513. //    function value.
  514. //
  515. // Arguments:
  516. //
  517. //    ListHead (a0) - Supplies a pointer to the head of the doubly linked
  518. //       list from which an entry is to be removed.
  519. //
  520. //    Lock (a1) - Supplies a pointer to a spin lock to be used to synchronize
  521. //       access to the list.
  522. //
  523. // Return Value:
  524. //
  525. //    The address of the entry removed from the list, or NULL if the list is
  526. //    empty.
  527. //
  528. //--
  529.         LEAF_ENTRY(ExInterlockedRemoveHeadList)
  530. 5:      DISABLE_INTERRUPTS(t0)          // disable interrupts
  531. #if !defined(NT_UP)
  532. 10:     ll      t2,0(a1)                // get current lock value
  533.         move    t3,a1                   // set ownership value
  534.         bne     zero,t2,30f             // if ne, spin lock owned
  535.         sc      t3,0(a1)                // set spin lock owned
  536.         beq     zero,t3,10b             // if eq, store conditional failed
  537. #endif
  538.         lw      t2,LsFlink(a0)          // get address of next entry
  539.         move    v0,zero                 // assume list is empty
  540.         beq     t2,a0,20f               // if eq, list is empty
  541.         lw      t3,LsFlink(t2)          // get address of next entry
  542.         sw      t3,LsFlink(a0)          // store address of next in head
  543.         sw      a0,LsBlink(t3)          // store address of previous in next
  544.         move    v0,t2                   // set address of entry removed
  545. 20:                                     //
  546. #if !defined(NT_UP)
  547.         sw      zero,0(a1)              // set spin lock not owned
  548. #endif
  549.         ENABLE_INTERRUPTS(t0)           // enable interrupts
  550.         j       ra                      // return
  551. #if !defined(NT_UP)
  552. 30:     ENABLE_INTERRUPTS(t0)           // enable interrupts
  553.         b       5b                      // try again
  554. #endif
  555.         .end    ExInterlockedRemoveHeadList
  556.         SBTTL("Interlocked Pop Entry List")
  557. //++
  558. //
  559. // PSINGLE_LIST_ENTRY
  560. // ExInterlockedPopEntryList (
  561. //    IN PSINGLE_LIST_ENTRY ListHead,
  562. //    IN PKSPIN_LOCK Lock
  563. //    )
  564. //
  565. // Routine Description:
  566. //
  567. //    This function removes an entry from the front of a singly linked list
  568. //    so that access to the list is synchronized in a multiprocessor system.
  569. //    If there are no entries in the list, then a value of NULL is returned.
  570. //    Otherwise, the address of the entry that is removed is returned as the
  571. //    function value.
  572. //
  573. // Arguments:
  574. //
  575. //    ListHead (a0) - Supplies a pointer to the head of the singly linked
  576. //       list from which an entry is to be removed.
  577. //
  578. //    Lock (a1) - Supplies a pointer to a spin lock to be used to synchronize
  579. //       access to the list.
  580. //
  581. // Return Value:
  582. //
  583. //    The address of the entry removed from the list, or NULL if the list is
  584. //    empty.
  585. //
  586. //--
  587.         LEAF_ENTRY(ExInterlockedPopEntryList)
  588. 5:      DISABLE_INTERRUPTS(t0)          // disable interrupts
  589. #if !defined(NT_UP)
  590. 10:     ll      t2,0(a1)                // get current lock value
  591.         move    t3,a1                   // set ownership value
  592.         bne     zero,t2,30f             // if ne, spin lock owned
  593.         sc      t3,0(a1)                // set spin lock owned
  594.         beq     zero,t3,10b             // if eq, store conditional failed
  595. #endif
  596.         lw      v0,0(a0)                // get address of next entry
  597.         beq     zero,v0,20f             // if eq, list is empty
  598.         lw      t2,0(v0)                // get address of next entry
  599.         sw      t2,0(a0)                // store address of next in head
  600. 20:                                     //
  601. #if !defined(NT_UP)
  602.         sw      zero,0(a1)              // set spin lock not owned
  603. #endif
  604.         ENABLE_INTERRUPTS(t0)           // enable interrupts
  605.         j       ra                      // return
  606. #if !defined(NT_UP)
  607. 30:     ENABLE_INTERRUPTS(t0)           // enable interrupts
  608.         b       5b                      // try again
  609. #endif
  610.         .end    ExInterlockedPopEntryList
  611.         SBTTL("Interlocked Push Entry List")
  612. //++
  613. //
  614. // PSINGLE_LIST_ENTRY
  615. // ExInterlockedPushEntryList (
  616. //    IN PSINGLE_LIST_ENTRY ListHead,
  617. //    IN PSINGLE_LIST_ENTRY ListEntry,
  618. //    IN PKSPIN_LOCK Lock
  619. //    )
  620. //
  621. // Routine Description:
  622. //
  623. //    This function inserts an entry at the head of a singly linked list
  624. //    so that access to the list is synchronized in a multiprocessor system.
  625. //
  626. // Arguments:
  627. //
  628. //    ListHead (a0) - Supplies a pointer to the head of the singly linked
  629. //       list into which an entry is to be inserted.
  630. //
  631. //    ListEntry (a1) - Supplies a pointer to the entry to be inserted at the
  632. //       head of the list.
  633. //
  634. //    Lock (a2) - Supplies a pointer to a spin lock to be used to synchronize
  635. //       access to the list.
  636. //
  637. // Return Value:
  638. //
  639. //    Previous contents of ListHead.  NULL implies list went from empty
  640. //       to not empty.
  641. //
  642. //--
  643.         LEAF_ENTRY(ExInterlockedPushEntryList)
  644. 5:      DISABLE_INTERRUPTS(t0)          // disable interrupts
  645. #if !defined(NT_UP)
  646. 10:     ll      t2,0(a2)                // get current lock value
  647.         move    t3,a2                   // set ownership value
  648.         bne     zero,t2,20f             // if ne, spin lock owned
  649.         sc      t3,0(a2)                // set spin lock owned
  650.         beq     zero,t3,10b             // if eq, store conditional failed
  651. #endif
  652.         lw      v0,0(a0)                // get address of first entry (return value also)
  653.         sw      v0,0(a1)                // set address of next in new entry
  654.         sw      a1,0(a0)                // set address of first entry
  655. #if !defined(NT_UP)
  656.         sw      zero,0(a2)              // set spin lock not owned
  657. #endif
  658.         ENABLE_INTERRUPTS(t0)           // enable interrupts
  659.         j       ra                      // return
  660. #if !defined(NT_UP)
  661. 20:     ENABLE_INTERRUPTS(t0)           // enable interrupts
  662.         b       5b                      // try again
  663. #endif
  664.         .end    ExInterlockedPushEntryList
  665.         SBTTL("Interlocked Pop Entry Sequenced List")
  666. //++
  667. //
  668. // PSINGLE_LIST_ENTRY
  669. // ExpInterlockedPopEntrySList (
  670. //    IN PSLIST_HEADER ListHead
  671. //    )
  672. //
  673. // Routine Description:
  674. //
  675. //    This function removes an entry from the front of a sequenced singly
  676. //    linked list so that access to the list is synchronized in a MP system.
  677. //    If there are no entries in the list, then a value of NULL is returned.
  678. //    Otherwise, the address of the entry that is removed is returned as the
  679. //    function value.
  680. //
  681. // Arguments:
  682. //
  683. //    ListHead (a0) - Supplies a pointer to the sequenced listhead from which
  684. //       an entry is to be removed.
  685. //
  686. // Return Value:
  687. //
  688. //    The address of the entry removed from the list, or NULL if the list is
  689. //    empty.
  690. //
  691. //--
  692.         LEAF_ENTRY(ExpInterlockedPopEntrySList)
  693.         .set    noreorder
  694.         .set    noat
  695. //
  696. // N.B. The following code is the continuation address should a fault
  697. //      occur in the rare case described below.
  698. //
  699.         ALTERNATE_ENTRY(ExpInterlockedPopEntrySListResume)
  700. 10:     ld      t0,0(a0)                // get next entry address and sequence
  701. 20:     dsll    v0,t0,32                // sign extend next entry address
  702.         dsra    v0,v0,32                //
  703.         beq     zero,v0,30f             // if eq, list is empty
  704.         dsrl    t1,t0,32                // shift sequence to low 32-bits
  705. //
  706. // N.B. It is possible for the following instruction to fault in the rare
  707. //      case where the first entry in the list is allocated on another
  708. //      processor and freed between the time the free pointer is read above
  709. //      and the following instruction. When this happens, the access fault
  710. //      code continues execution above at the resumption address and the
  711. //      entire operation is retried.
  712. //
  713.         ALTERNATE_ENTRY(ExpInterlockedPopEntrySListFault)
  714.         lwu     t2,0(v0)                // get address of successor entry
  715.         lld     t3,0(a0)                // reload next entry address and sequence
  716.         li      t4,0xffff               // decrement list depth and
  717.         addu    t1,t1,t4                // increment sequence number
  718.         dsll    t1,t1,32                // merge successor address and sequence
  719.         bne     t0,t3,10b               // if ne, listhead has changed
  720.         or      t1,t1,t2                //
  721.         scd     t1,0(a0)                // store next emtry address and sequence
  722.         beql    zero,t1,20b             // if eq, store conditional failed
  723.         ld      t0,0(a0)                // get next entry address and sequence
  724.         .set    at
  725.         .set    reorder
  726. 30:     j       ra                      // return
  727.         .end    ExpInterlockedPopEntrySList
  728.         SBTTL("Interlocked Push Entry Sequenced List")
  729. //++
  730. //
  731. // PSINGLE_LIST_ENTRY
  732. // ExpInterlockedPushEntrySList (
  733. //    IN PSLIST_HEADER ListHead,
  734. //    IN PSINGLE_LIST_ENTRY ListEntry
  735. //    )
  736. //
  737. // Routine Description:
  738. //
  739. //    This function inserts an entry at the head of a sequenced singly linked
  740. //    list so that access to the list is synchronized in an MP system.
  741. //
  742. // Arguments:
  743. //
  744. //    ListHead (a0) - Supplies a pointer to the sequenced listhead into which
  745. //       an entry is to be inserted.
  746. //
  747. //    ListEntry (a1) - Supplies a pointer to the entry to be inserted at the
  748. //       head of the list.
  749. //
  750. // Return Value:
  751. //
  752. //    Previous contents of ListHead.  NULL implies list went from empty
  753. //       to not empty.
  754. //
  755. //--
  756.         LEAF_ENTRY(ExpInterlockedPushEntrySList)
  757.         .set    noreorder
  758.         .set    noat
  759. 10:     ld      t0,0(a0)                // get next entry address and sequence
  760. 20:     dsll    v0,t0,32                // sign extend next entry address
  761.         dsra    v0,v0,32                //
  762.         dsrl    t1,t0,32                // shift sequence to low 32-bits
  763.         sw      v0,0(a1)                // set next link in new first entry
  764.         dsll    t2,a1,32                // zero extend new first entry
  765.         dsrl    t2,t2,32                //
  766.         lld     t3,0(a0)                // reload next entry address and sequence
  767.         lui     t4,1                    // get sequence adjustment value
  768.         addu    t1,t1,1                 // increment list depth
  769.         addu    t1,t1,t4                // increment sequence number
  770.         dsll    t1,t1,32                // merge new first entry address and sequence
  771.         bne     t0,t3,10b               // if ne, listhead has changed
  772.         or      t1,t1,t2                //
  773.         scd     t1,0(a0)                // store next emtry address and sequence
  774.         beql    zero,t1,20b             // if eq, store conditional failed
  775.         ld      t0,0(a0)                // get next entry address and sequence
  776.         .set    at
  777.         .set    reorder
  778.         j       ra                      // return
  779.         .end    ExpInterlockedPushEntrySList
  780.         SBTTL("Interlocked Compare Exchange 64-bits")
  781. //++
  782. //
  783. // ULONGLONG
  784. // ExpInterlockedCompareExchange64 (
  785. //    IN PULONGLONG Destination,
  786. //    IN PULONGLONG Exchange,
  787. //    IN PULONGLONG Comperand
  788. //    )
  789. //
  790. // Routine Description:
  791. //
  792. //    This function performs an interlocked compare and exchange of 64-bits.
  793. //
  794. // Arguments:
  795. //
  796. //    Destination (a0) - Supplies a pointer to the destination variable.
  797. //
  798. //    Exchange (a1) - Supplies a pointer to the exchange value.
  799. //
  800. //    Comperand (a2) - Supplies a pointer to the comperand value.
  801. //
  802. // Return Value:
  803. //
  804. //    The current destination value are returned as the function value.
  805. //
  806. //--
  807.         LEAF_ENTRY(ExpInterlockedCompareExchange64)
  808.         .set    noreorder
  809.         .set    noat
  810.         ld      t0,0(a1)                // get exchange value
  811.         ld      t1,0(a2)                // get comperand value
  812.         lld     v0,0(a0)                // get current destination value
  813. 10:     move    t2,t0                   // set exchange value
  814.         bne     v0,t1,20f               // if ne, current and comperand mismatch
  815.         dsra    v1,v0,32                // extract high part of result
  816.         scd     t2,0(a0)                // store exchange value
  817.         beql    zero,t2,10b             // if eq, store conditional failed
  818.         lld     v0,0(a0)                // get next entry address and sequence
  819. 20:     dsll    v0,v0,32                // extract low part of result
  820.         j       ra                      // return
  821.         dsra    v0,v0,32                //
  822.         .set    at
  823.         .set    reorder
  824.         .end    ExpInterlockedCompareExchange64