Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

468 lines
14 KiB

  1. // TITLE("Interlocked Support")
  2. //++
  3. //
  4. // Copyright (c) 1998 Intel Corporation
  5. // Copyright (c) 1998 Microsoft Corporation
  6. //
  7. // Module Name:
  8. //
  9. // slist.s
  10. //
  11. // Abstract:
  12. //
  13. // This module implements functions to support interlocked S_List
  14. // operations.
  15. //
  16. // Author:
  17. //
  18. // William K. Cheung (v-wcheung) 10-Mar-1998
  19. //
  20. // Environment:
  21. //
  22. // User mode.
  23. //
  24. // Revision History:
  25. //
  26. //--
  27. #include "ksia64.h"
  28. //
  29. // Define how big the depth field. This is the start of the word
  30. //
  31. #define SLIST_DEPTH_BITS_SIZE 16
  32. //
  33. // Define the start of the pointer in an slist
  34. //
  35. #define SLIST_ADR_BITS_START 25
  36. //
  37. // Define the number of alignment bits for an address
  38. //
  39. #define SLIST_ADR_ALIGMENT 4
  40. //
  41. // Define were the sequence bits start and how many there are
  42. //
  43. #define SLIST_SEQ_BITS_START 16
  44. #define SLIST_SEQ_BITS_SIZE 9
  45. //++
  46. //
  47. // PSINGLE_LIST_ENTRY
  48. // RtlpInterlockedFlushSList (
  49. // IN PSLIST_HEADER ListHead
  50. // )
  51. //
  52. // Routine Description:
  53. //
  54. // This function flushes the entire list of entries on a sequenced singly
  55. // linked list so that access to the list is synchronized in a MP system.
  56. // If there are no entries in the list, then a value of NULL is returned.
  57. // Otherwise, the address of the 1st entry on the list is returned as the
  58. // function value.
  59. //
  60. // Arguments:
  61. //
  62. // ListHead (a0) - Supplies a pointer to the sequenced listhead from which
  63. // an current list is to be removed.
  64. //
  65. // Return Value:
  66. //
  67. // The address of the 1st entry on the list, or NULL if the list is
  68. // empty.
  69. //
  70. //--
  71. LEAF_ENTRY(RtlpInterlockedFlushSList)
  72. ALTERNATE_ENTRY(ExpInterlockedFlushSList)
  73. ld8.acq.nt1 t0 = [a0] // load next entry & sequence
  74. #if defined (NTOS_KERNEL_RUNTIME)
  75. add t1 = 8, a0 // Get address of region cell
  76. #endif
  77. ;;
  78. #if defined (NTOS_KERNEL_RUNTIME)
  79. ld8 t1 = [t1] // Load region bits
  80. #endif
  81. mov ar.ccv = t0
  82. shr.u v0 = t0, SLIST_ADR_BITS_START
  83. ;;
  84. Efls10:
  85. cmp.eq pt1 = v0, r0 // if eq, list is empty
  86. extr.u t5 = t0, SLIST_SEQ_BITS_START, \
  87. SLIST_SEQ_BITS_SIZE // extract the sequence number
  88. (pt1) br.ret.spnt.clr brp // return if the list is null
  89. ;;
  90. #if defined (NTOS_KERNEL_RUNTIME)
  91. shladd v0 = v0, SLIST_ADR_ALIGMENT, t1 // merge region & va bits
  92. #else
  93. shl v0 = v0, SLIST_ADR_ALIGMENT // shift address into place
  94. #endif
  95. shl t5 = t5, SLIST_SEQ_BITS_START // shift sequence number into place
  96. ;;
  97. cmpxchg8.rel t3 = [a0], t5, ar.ccv // perform the pop
  98. ;;
  99. cmp.eq pt1, pt2 = t3, t0 // if eq, cmpxchg8 succeeded
  100. ;;
  101. (pt2) mov ar.ccv = t3
  102. (pt1) br.ret.sptk brp
  103. ;;
  104. mov t0 = t3
  105. shr.u v0 = t3, SLIST_ADR_BITS_START
  106. br Efls10 // try again
  107. LEAF_EXIT(RtlpInterlockedFlushSList)
  108. SBTTL("Interlocked Pop Entry Sequenced List")
  109. //++
  110. //
  111. // PSINGLE_LIST_ENTRY
  112. // RtlpInterlockedPopEntrySList (
  113. // IN PSLIST_HEADER ListHead
  114. // )
  115. //
  116. // Routine Description:
  117. //
  118. // This function removes an entry from the front of a sequenced singly
  119. // linked list so that access to the list is synchronized in a MP system.
  120. // If there are no entries in the list, then a value of NULL is returned.
  121. // Otherwise, the address of the entry that is removed is returned as the
  122. // function value.
  123. //
  124. // Arguments:
  125. //
  126. // ListHead (a0) - Supplies a pointer to the sequenced listhead from which
  127. // an entry is to be removed.
  128. //
  129. // Return Value:
  130. //
  131. // The address of the entry removed from the list, or NULL if the list is
  132. // empty.
  133. //
  134. //--
  135. LEAF_ENTRY(RtlpInterlockedPopEntrySList)
  136. ALTERNATE_ENTRY(ExpInterlockedPopEntrySList)
  137. ALTERNATE_ENTRY(ExpInterlockedPopEntrySListResume)
  138. ld8.acq.nt1 t0 = [a0] // load next entry & sequence
  139. #if defined (NTOS_KERNEL_RUNTIME)
  140. add t1 = 8, a0 // Generate address region bits
  141. #endif
  142. ;;
  143. Epop10:
  144. #if defined (NTOS_KERNEL_RUNTIME)
  145. ld8 t1 = [t1] // capture region bits
  146. #endif
  147. mov ar.ccv = t0
  148. shr.u t2 = t0, SLIST_ADR_BITS_START
  149. ;;
  150. #if defined (NTOS_KERNEL_RUNTIME)
  151. shladd v0 = t2, SLIST_ADR_ALIGMENT, t1 // merge region & va bits
  152. #else
  153. shl v0 = t2, SLIST_ADR_ALIGMENT // shift va into place
  154. #endif
  155. ;;
  156. #if defined (NTOS_KERNEL_RUNTIME)
  157. cmp.eq pt2, pt1 = t1, v0 // if eq, list is empty
  158. #else
  159. cmp.eq pt2, pt1 = r0, v0 // if eq, list is empty
  160. #endif
  161. sub t4 = t0, zero, 1 // adjust depth
  162. ;;
  163. //
  164. // N.B. It is possible for the following instruction to fault in the rare
  165. // case where the first entry in the list is allocated on another
  166. // processor and free between the time the free pointer is read above
  167. // and the following instruction. When this happens, the access fault
  168. // code continues execution by skipping the following instruction slot.
  169. // This results in the compare failing and the entire operation is
  170. // retried.
  171. //
  172. ALTERNATE_ENTRY(ExpInterlockedPopEntrySListFault)
  173. (pt1) ld8.acq t5 = [v0] // get addr of successor entry
  174. extr.u t4 = t4, 0, SLIST_DEPTH_BITS_SIZE + \
  175. SLIST_SEQ_BITS_SIZE // extract depth & sequence
  176. ;;
  177. (pt1) shl t5 = t5, SLIST_ADR_BITS_START - \
  178. SLIST_ADR_ALIGMENT // shift va into position dropping alignment bits
  179. (pt2) add v0 = 0, zero // The list is empty clear retur value
  180. ;;
  181. (pt1) ld8.nt1 t3 = [a0] // reload next entry & sequence
  182. (pt1) or t5 = t4, t5 // merge va, depth & sequence
  183. (pt2) br.ret.spnt.clr brp // return if the list is null
  184. ;;
  185. cmp.eq.unc pt4, pt1 = t3, t0
  186. ;;
  187. ALTERNATE_ENTRY(ExpInterlockedPopEntrySListEnd)
  188. (pt4) cmpxchg8.rel t3 = [a0], t5, ar.ccv // perform the pop
  189. nop.i 0
  190. ;;
  191. (pt4) cmp.eq.unc pt3 = t3, t0 // if eq, cmpxchg8 succeeded
  192. #if defined (NTOS_KERNEL_RUNTIME)
  193. add t1 = 8, a0
  194. #endif
  195. mov t0 = t3
  196. (pt3) br.ret.sptk brp
  197. br Epop10 // try again
  198. LEAF_EXIT(RtlpInterlockedPopEntrySList)
  199. //++
  200. //
  201. // PSINGLE_LIST_ENTRY
  202. // RtlpInterlockedPushEntrySList (
  203. // IN PSLIST_HEADER ListHead,
  204. // IN PSINGLE_LIST_ENTRY ListEntry
  205. // )
  206. //
  207. // Routine Description:
  208. //
  209. // This function inserts an entry at the head of a sequenced singly linked
  210. // list so that access to the list is synchronized in an MP system.
  211. //
  212. // Arguments:
  213. //
  214. // ListHead (a0) - Supplies a pointer to the sequenced listhead into which
  215. // an entry is to be inserted.
  216. //
  217. // ListEntry (a1) - Supplies a pointer to the entry to be inserted at the
  218. // head of the list.
  219. //
  220. // Return Value:
  221. //
  222. // Previous contents of ListHead. NULL implies list went from empty
  223. // to not empty.
  224. //
  225. //--
  226. LEAF_ENTRY(RtlpInterlockedPushEntrySList)
  227. ALTERNATE_ENTRY(ExpInterlockedPushEntrySList)
  228. ld8.acq.nt1 t0 = [a0] // load next entry & sequence
  229. mov t6 = (1<<SLIST_SEQ_BITS_START)+1 // Increment sequence and depth
  230. ldf.fill ft0 = [a1] // Force alignment check.
  231. shl t5 = a1, SLIST_ADR_BITS_START - \
  232. SLIST_ADR_ALIGMENT // shift va into position
  233. ;;
  234. #if DBG==1
  235. and t3 = (1<<SLIST_ADR_ALIGMENT)-1, a1
  236. add t2 = 8, a0
  237. dep t1 = 0, a1, 0, 61 // capture region bits
  238. ;;
  239. cmp.eq pt2, pt1 = t3, r0
  240. #if defined (NTOS_KERNEL_RUNTIME)
  241. ld8 t2 = [t2]
  242. ;;
  243. (pt2) cmp.eq pt2, pt1 = t2, t1
  244. #endif
  245. ;;
  246. (pt1) break.i 0x80016
  247. #endif
  248. Epush10:
  249. mov ar.ccv = t0 // set the comparand
  250. add t4 = t0, t6
  251. shr.u v0 = t0, SLIST_ADR_BITS_START
  252. ;;
  253. #if defined (NTOS_KERNEL_RUNTIME)
  254. dep t1 = 0, a1, 0, 61 // capture region bits
  255. #endif
  256. cmp.ne pt3 = zero, v0 // if ne, list not empty
  257. ;;
  258. #if defined (NTOS_KERNEL_RUNTIME)
  259. (pt3) shladd v0 = v0, SLIST_ADR_ALIGMENT, t1 // merge region & va bits
  260. #else
  261. (pt3) shl v0 = v0, SLIST_ADR_ALIGMENT // shift address into place
  262. #endif
  263. extr.u t4 = t4, 0, SLIST_DEPTH_BITS_SIZE + \
  264. SLIST_SEQ_BITS_SIZE // extract depth & sequence
  265. ;;
  266. st8 [a1] = v0
  267. or t5 = t4, t5 // merge va, depth & sequence
  268. ;;
  269. cmpxchg8.rel t3 = [a0], t5, ar.ccv
  270. ;;
  271. cmp.eq pt2, pt1 = t0, t3
  272. dep t5 = 0, t5, 0, SLIST_DEPTH_BITS_SIZE + \
  273. SLIST_SEQ_BITS_SIZE // Zero depth a sequence
  274. ;;
  275. (pt2) br.ret.sptk brp // if equal, return
  276. (pt1) mov t0 = t3
  277. (pt1) br.spnt Epush10 // retry
  278. ;;
  279. LEAF_EXIT(RtlpInterlockedPushEntrySList)
  280. //++
  281. //
  282. // SINGLE_LIST_ENTRY
  283. // FASTCALL
  284. // InterlockedPushListSList (
  285. // IN PSLIST_HEADER ListHead,
  286. // IN PSINGLE_LIST_ENTRY List,
  287. // IN PSINGLE_LIST_ENTRY ListEnd,
  288. // IN ULONG Count
  289. // )
  290. //
  291. // Routine Description:
  292. //
  293. // This function will push multiple entries onto an SList at once
  294. //
  295. // Arguments:
  296. //
  297. // ListHead - List head to push the list to.
  298. //
  299. // List - The list to add to the front of the SList
  300. // ListEnd - The last element in the chain
  301. // Count - The number of items in the chain
  302. //
  303. // Return Value:
  304. //
  305. // PSINGLE_LIST_ENTRY - The old header pointer is returned
  306. //
  307. //--
  308. LEAF_ENTRY(InterlockedPushListSList)
  309. ld8.acq.nt1 t0 = [a0] // load next entry & sequence
  310. mov t6 = 0x10000 // Generate literal for adjusting depth and count
  311. ldf.fill ft0 = [a1] // Force alignment check.
  312. shl t5 = a1, SLIST_ADR_BITS_START - \
  313. SLIST_ADR_ALIGMENT // shift va into position
  314. ;;
  315. #if DBG==1
  316. and t3 = (1<<SLIST_ADR_ALIGMENT)-1, a1
  317. add t2 = 8, a0
  318. dep t1 = 0, a1, 0, 61 // capture region bits
  319. ;;
  320. cmp.eq pt2, pt1 = t3, r0
  321. #if defined (NTOS_KERNEL_RUNTIME)
  322. ld8 t2 = [t2]
  323. ;;
  324. (pt2) cmp.eq pt2, pt1 = t2, t1
  325. #endif
  326. ;;
  327. (pt1) break.i 0x80016
  328. #endif
  329. Epushl10:
  330. mov ar.ccv = t0 // set the comparand
  331. add t4 = t0, t6
  332. shr.u v0 = t0, SLIST_ADR_BITS_START
  333. ;;
  334. #if defined (NTOS_KERNEL_RUNTIME)
  335. dep t1 = 0, a1, 0, 61 // capture region bits
  336. #endif
  337. cmp.ne pt3 = zero, v0 // if ne, list not empty
  338. add t4 = t4, a3 // Add in count
  339. ;;
  340. #if defined (NTOS_KERNEL_RUNTIME)
  341. (pt3) shladd v0 = v0, SLIST_ADR_ALIGMENT, t1 // merge region & va bits
  342. #else
  343. (pt3) shl v0 = v0, SLIST_ADR_ALIGMENT // shift address into place
  344. #endif
  345. extr.u t4 = t4, 0, SLIST_DEPTH_BITS_SIZE + \
  346. SLIST_SEQ_BITS_SIZE // extract depth & sequence
  347. ;;
  348. st8 [a2] = v0
  349. or t5 = t4, t5 // merge va, depth & sequence
  350. ;;
  351. cmpxchg8.rel t3 = [a0], t5, ar.ccv
  352. ;;
  353. cmp.eq pt2, pt1 = t0, t3
  354. dep t5 = 0, t5, 0, SLIST_DEPTH_BITS_SIZE + \
  355. SLIST_SEQ_BITS_SIZE // zero depth and sequence
  356. mov t0 = t3
  357. (pt2) br.ret.sptk brp // if equal, return
  358. (pt1) br.spnt Epushl10 // retry
  359. ;;
  360. LEAF_EXIT(InterlockedPushListSList)
  361. //++
  362. //
  363. // PSINGLE_LIST_ENTRY
  364. // FirstEntrySList (
  365. // IN PSLIST_HEADER SListHead
  366. // )
  367. //
  368. // Routine Description:
  369. //
  370. // This function returns the address of the fisrt entry in the SLIST or
  371. // NULL.
  372. //
  373. // Arguments:
  374. //
  375. // ListHead - Supplies a pointer to the sequenced listhead from
  376. // which the first entry address is to be computed.
  377. //
  378. // Return Value:
  379. //
  380. // The address of the first entry is the specified, or NULL if the list is
  381. // empty.
  382. //
  383. //--
  384. LEAF_ENTRY(FirstEntrySList)
  385. ld8 t0 = [a0] // load next entry & sequence
  386. #if defined (NTOS_KERNEL_RUNTIME)
  387. add t1 = 8, a0 // Generate address region bits
  388. #endif
  389. ;;
  390. #if defined (NTOS_KERNEL_RUNTIME)
  391. ld8 t1 = [t1] // capture region bits
  392. #endif
  393. shr.u t2 = t0, SLIST_ADR_BITS_START
  394. ;;
  395. #if defined (NTOS_KERNEL_RUNTIME)
  396. cmp.eq pt0 = t2, r0
  397. shladd v0 = t2, SLIST_ADR_ALIGMENT, t1 // merge region & va bits
  398. #else
  399. shl v0 = t2, SLIST_ADR_ALIGMENT // shift va into place
  400. #endif
  401. ;;
  402. #if defined (NTOS_KERNEL_RUNTIME)
  403. (pt0) mov v0 = r0
  404. #endif
  405. br.ret.sptk brp // return function value
  406. LEAF_EXIT(FirstEntrySList)