Source code of Windows XP (NT5)
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.

826 lines
20 KiB

  1. //
  2. // Copyright (c) 1992 Microsoft Corporation
  3. //
  4. // Module Name:
  5. //
  6. // lockhelp.s
  7. //
  8. // Abstract:
  9. //
  10. // This module contains the assembly code for the 32bit lock instructions.
  11. // We must used assembly code here because of the need for
  12. // synchronization (we need ldl_l and stl_c)
  13. //
  14. // Author:
  15. //
  16. // Dave Hastings (daveh) creation-date 05-Sep-1995
  17. // From ..\mips\lockhelp.s
  18. //
  19. // Notes:
  20. // The failure case for the store conditional is a forward jump, because
  21. // AXP predicts that forward conditional jumps will not be taken, and
  22. // backwards conditional jumps will be taken
  23. //
  24. // Revision History:
  25. #include "kxalpha.h"
  26. #include "soalpha.h"
  27. .text
  28. #define FRAGLOCK(fn) FRAGMENT(fn ## LockHelper)
  29. #define ENDFRAGLOCK(fn) END_FRAGMENT(fn ## LockHelper)
  30. //
  31. // Debug only macros to allow verification that we aren't iterating forever
  32. //
  33. #define ITCHK_INIT
  34. #define ITCHK
  35. .set noreorder
  36. FRAGLOCK(Add)
  37. //
  38. // Routine Description:
  39. //
  40. // This routine adds its two arguments and places the result
  41. // in the memory pointed to by pop1 if its content hasn't changed.
  42. // It also returns the value of op1 for flag calculation
  43. //
  44. // Arguments:
  45. //
  46. // &op1 <a0> -- Pointer to place to store value of op1 once it it
  47. // retreived from memory. It is used by the sign
  48. // calculation
  49. // pop1 <a1> -- A pointer to op1
  50. // op2 <a2> -- The immediate to add to op1
  51. //
  52. // Return Value:
  53. //
  54. // v0 contains the sum of op1 and op2
  55. //
  56. ITCHK_INIT
  57. //
  58. // Get the value of op1
  59. // add it to op2
  60. // store the value in op1
  61. // if the value of op1 changed between load and store, try again
  62. //
  63. la01: ldl_l t0, (a1)
  64. addl a2, t0, t1
  65. bis t1, zero, v0
  66. stl_c t1, (a1)
  67. beq t1, la02
  68. //
  69. // return the value of op1 for the flags calculation
  70. //
  71. stl t0, (a0)
  72. ret zero, (ra)
  73. //
  74. // Someone else modified (or might have modified) the location
  75. // we're trying to atomically modify
  76. //
  77. la02: ITCHK
  78. br zero, la01
  79. ENDFRAGLOCK(Add)
  80. FRAGLOCK(Or)
  81. //
  82. // Routine Description:
  83. //
  84. // This routine ors its two arguments and places the result
  85. // in the memory pointed to by pop1 if its content hasn't changed.
  86. //
  87. // Arguments:
  88. //
  89. // pop1 <a0> -- A pointer to op1
  90. // op2 <a1> -- The immediate to add to op1
  91. //
  92. // Return Value:
  93. //
  94. // v0 contains (op1 | op2)
  95. //
  96. ITCHK_INIT
  97. //
  98. // Get the value of op1
  99. // or it to op2
  100. // store the value in op1
  101. // if the value of op1 changed between load and store, try again
  102. //
  103. lo01: ldl_l t0, (a0)
  104. bis a1, t0, t1
  105. bis t1, zero, v0
  106. stl_c t1, (a0)
  107. beq t1, lo02
  108. ret zero, (ra)
  109. //
  110. // Someone else modified (or might have modified) the location
  111. // we're trying to atomically modify
  112. //
  113. lo02: ITCHK
  114. br zero, lo01
  115. ENDFRAGLOCK(Or)
  116. FRAGLOCK(Adc)
  117. //
  118. // Routine Description:
  119. //
  120. // This routine adds its two arguments and carry, and places the result
  121. // in the memory pointed to by pop1 if its content hasn't changed.
  122. // It also returns the value of op1 for flag calculation.
  123. //
  124. // Arguments:
  125. //
  126. // &op1 <a0> -- Pointer to place to store value of op1 once it it
  127. // retreived from memory. It is used by the sign
  128. // calculation
  129. // pop1 <a1> -- A pointer to op1
  130. // op2 <a2> -- The immediate to add to op1
  131. // carry<a3> -- The value of the carry flag
  132. //
  133. // Return Value:
  134. //
  135. // v0 contains (op1 + op2 + carry)
  136. //
  137. ITCHK_INIT
  138. //
  139. // Get the value of op1
  140. // add it to op2 and carry
  141. // store it back into op1
  142. // if the value of op1 changed between load and store, try again
  143. //
  144. lac01: ldl_l t0, (a1)
  145. addl a2, t0, t1
  146. addl t1, a3, t1
  147. bis t1, zero, v0
  148. stl_c t1, (a1)
  149. beq t1, lac02
  150. //
  151. // return the value of op1 for sign calculation
  152. //
  153. stl t0, (a0)
  154. ret zero, (ra)
  155. //
  156. // Someone else modified (or might have modified) the location
  157. // we're trying to atomically modify
  158. //
  159. lac02: ITCHK
  160. br zero, lac01
  161. ENDFRAGLOCK(Adc)
  162. FRAGLOCK(Sbb)
  163. //
  164. // Routine Description:
  165. //
  166. // This routine subtracts op2+carry from op1 and places the result
  167. // in the memory pointed to by pop1 if its content hasn't changed.
  168. // It also returns the value of op1 for use in flag calculation.
  169. //
  170. // Arguments:
  171. //
  172. // &op1 <a0> -- A place to store the content of op1 once determined
  173. // pop1 <a1> -- A pointer op1
  174. // op2 <a2> -- The immediate to add to op1
  175. // carry<a3> -- The value of the carry flag
  176. //
  177. // Return Value:
  178. //
  179. // v0 contains op1 - (op2 + carry)
  180. //
  181. ITCHK_INIT
  182. //
  183. // Get the value of op1
  184. // subtract op2 and carry
  185. // store it back into op1
  186. // if the value of op1 changed between load and store, try again
  187. //
  188. sbb01: ldl_l t0, (a1)
  189. subl t0, a2, t1
  190. subl t1, a3, t1
  191. bis t1, zero, v0
  192. stl_c t1, (a1)
  193. beq t1, sbb02
  194. //
  195. // return the value of op1 for sign calculation
  196. //
  197. stl t0, (a0)
  198. ret zero, (ra)
  199. //
  200. // Someone else modified (or might have modified) the location
  201. // we're trying to atomically modify
  202. //
  203. sbb02: ITCHK
  204. br zero, sbb01
  205. ENDFRAGLOCK(Sbb)
  206. FRAGLOCK(And)
  207. //
  208. // Routine Description:
  209. //
  210. // This routine ands its two arguments and places the result
  211. // in the memory pointed to by pop1 if its content hasn't changed.
  212. //
  213. // Arguments:
  214. //
  215. // pop1 <a0> -- A pointer to the content of op1
  216. // op2 <a1> -- The immediate to add to op1
  217. //
  218. // Return Value:
  219. //
  220. // v0 contains (op1 & op2)
  221. //
  222. ITCHK_INIT
  223. //
  224. // get the value of op1
  225. // and it with op2
  226. // store the result in op1
  227. // if the value of op1 changed between load and store, try again
  228. //
  229. and01: ldl_l t0, (a0)
  230. and t0, a1, t1
  231. bis t1, zero, v0
  232. stl_c t1, (a0)
  233. beq t1, and02
  234. ret zero, (ra)
  235. //
  236. // Someone else modified (or might have modified) the location
  237. // we're trying to atomically modify
  238. //
  239. and02: ITCHK
  240. br zero, and01
  241. ENDFRAGLOCK(And)
  242. FRAGLOCK(Sub)
  243. //
  244. // Routine Description:
  245. //
  246. // This routine subtracts op2 from op1 and places the result
  247. // in the memory pointed to by pop1 if its content hasn't changed.
  248. // It also returns the value of op1 for flag calculation.
  249. //
  250. // Arguments:
  251. //
  252. // &op1 <a0> -- A place to store the content of op1 once determined
  253. // pop1 <a1> -- A pointer to the content of op1
  254. // op2 <a2> -- The immediate to add to op1
  255. //
  256. // Return Value:
  257. //
  258. // v0 contains op1-op2
  259. //
  260. ITCHK_INIT
  261. //
  262. // get the value of op1
  263. // subtract op2
  264. // store the result in op1
  265. // if the value of op1 changed between load and store, try again
  266. //
  267. sub01: ldl_l t0, (a1)
  268. subl t0, a2, t1
  269. bis t1, zero, v0
  270. stl_c t1, (a1)
  271. beq t1, sub02
  272. //
  273. // return the value of op1 for sign calculation
  274. //
  275. stl t0, (a0)
  276. ret zero, (ra)
  277. //
  278. // Someone else modified (or might have modified) the location
  279. // we're trying to atomically modify
  280. //
  281. sub02: ITCHK
  282. br zero, sub01
  283. ENDFRAGLOCK(Sub)
  284. FRAGLOCK(Xor)
  285. //
  286. // Routine Description:
  287. //
  288. // This routine xors its two arguments and places the result
  289. // in the memory pointed to by pop1 if its content hasn't changed.
  290. //
  291. // Arguments:
  292. //
  293. // pop1 <a0> -- A pointer to the content of op1
  294. // op2 <a1> -- The immediate to add to op1
  295. //
  296. // Return Value:
  297. //
  298. // v0 contains (op1 ^ op2)
  299. //
  300. ITCHK_INIT
  301. //
  302. // get the value of op1
  303. // xor with op2
  304. // store the result in op1
  305. // if the value of op1 changed between load and store, try again
  306. //
  307. xor01: ldl_l t0, (a0)
  308. xor t0, a1, t1
  309. bis t1, zero, v0
  310. stl_c t1, (a0)
  311. beq t1, xor02
  312. ret zero, (ra)
  313. //
  314. // Someone else modified (or might have modified) the location
  315. // we're trying to atomically modify
  316. //
  317. xor02: ITCHK
  318. br zero, xor01
  319. ENDFRAGLOCK(Xor)
  320. FRAGLOCK(Not)
  321. //
  322. // Routine Description:
  323. //
  324. // This routine computes the NOT of op1 and stores it in pop1
  325. //
  326. // Arguments:
  327. //
  328. // pop1 <a0> -- A pointer to op1
  329. //
  330. // Return Value:
  331. //
  332. // none
  333. //
  334. ITCHK_INIT
  335. //
  336. // get the value of op1
  337. // not
  338. // store the result in op1
  339. // if the value of op1 changed between load and store, try again
  340. //
  341. not01: ldl_l t0, (a0)
  342. ornot zero, t0, t1
  343. stl_c t1, (a0)
  344. beq t1, not02
  345. ret zero, (ra)
  346. //
  347. // Someone else modified (or might have modified) the location
  348. // we're trying to atomically modify
  349. //
  350. not02: ITCHK
  351. br zero, not01
  352. ENDFRAGLOCK(Not)
  353. FRAGLOCK(Neg)
  354. //
  355. // Routine Description:
  356. //
  357. // This routine calculates the negative of op1 and stores it in pop1
  358. //
  359. // Arguments:
  360. //
  361. // &op1 <a0> -- A place to store the content of op1 once determined
  362. // pop1 <a1> -- A pointer to the content of op1
  363. //
  364. // Return Value:
  365. //
  366. // v0 contains -op1
  367. //
  368. ITCHK_INIT
  369. //
  370. // get value of op1
  371. // form two's complement
  372. // store the result in op1
  373. // if the value of op1 changed between load and store, try again
  374. //
  375. neg01: ldl_l t0, (a1)
  376. subl zero, t0, t1
  377. bis t1, zero, v0
  378. stl_c t1, (a1)
  379. //
  380. // return the value of op1 for sign calculation
  381. //
  382. stl t0, (a0)
  383. ret zero, (ra)
  384. //
  385. // Someone else modified (or might have modified) the location
  386. // we're trying to atomically modify
  387. //
  388. neg02: ITCHK
  389. br zero, neg01
  390. ENDFRAGLOCK(Neg)
  391. FRAGLOCK(Bts)
  392. //
  393. // Routine Description:
  394. //
  395. // This routine sets bit in op1 and stores it back into pop1. It returns
  396. // the original state of the bit in op1.
  397. //
  398. // Arguments:
  399. //
  400. // pop1 <a0> -- A pointer to the content of op1
  401. // bit <a1> -- The bit to set
  402. //
  403. // Return Value:
  404. //
  405. // The original "bit" bit in op1
  406. //
  407. ITCHK_INIT
  408. //
  409. // get the value of op1
  410. // set the bit
  411. // store the result in op1
  412. // if the value of op1 changed between load and store, try again
  413. //
  414. bts01: ldl_l t0, (a0)
  415. bis t0, a1, t1
  416. stl_c t1, (a0)
  417. beq t1, bts02
  418. //
  419. // return the original value of bit
  420. //
  421. and t0, a1, v0
  422. ret zero, (ra)
  423. //
  424. // Someone else modified (or might have modified) the location
  425. // we're trying to atomically modify
  426. //
  427. bts02: ITCHK
  428. br zero, bts01
  429. ENDFRAGLOCK(Bts)
  430. FRAGLOCK(Btr)
  431. //
  432. // Routine Description:
  433. //
  434. // This routine resets bit in op1 and stores it back into pop1. It returns
  435. // the original state of the bit in op1.
  436. //
  437. // Arguments:
  438. //
  439. // pop1 <a0> -- A pointer to the content of op1
  440. // bit <a1> -- The bit to reset
  441. //
  442. // Return Value:
  443. //
  444. // The original "bit" bit in op1
  445. //
  446. ITCHK_INIT
  447. //
  448. // get the value of op1
  449. // clear the bit
  450. // store the result in op1
  451. // if the value of op1 changed between load and store, try again
  452. //
  453. btr01: ldl_l t0, (a0)
  454. bic t0, a1, t1
  455. stl_c t1, (a0)
  456. beq t1, btr02
  457. //
  458. // return the original value of bit
  459. //
  460. and t0, a1, v0
  461. ret zero, (ra)
  462. //
  463. // Someone else modified (or might have modified) the location
  464. // we're trying to atomically modify
  465. //
  466. btr02: ITCHK
  467. br zero, btr01
  468. ENDFRAGLOCK(Btr)
  469. FRAGLOCK(Btc)
  470. //
  471. // Routine Description:
  472. //
  473. // This routine complements bit in op1 and stores it back into pop1. It returns
  474. // the original state of the bit in op1.
  475. //
  476. // Arguments:
  477. //
  478. // pop1 <a0> -- A pointer to the content of op1
  479. // bit <a1> -- The bit to complement
  480. //
  481. // Return Value:
  482. //
  483. // The original "bit" bit in op1
  484. //
  485. //
  486. // get the value of op1
  487. // complement the bit
  488. // store the result in op1
  489. // if the value of op1 changed between load and store, try again
  490. //
  491. btc01: ldl_l t0, (a0)
  492. xor t0, a1, t1
  493. stl_c t1, (a0)
  494. beq t1, btc02
  495. //
  496. // return after checking the bit
  497. //
  498. and t0, a1, v0
  499. ret zero, (ra)
  500. //
  501. // Someone else modified (or might have modified) the location
  502. // we're trying to atomically modify
  503. //
  504. btc02: ITCHK
  505. br zero, btc01
  506. ENDFRAGLOCK(Btc)
  507. FRAGLOCK(Xchg)
  508. //
  509. // Routine Description:
  510. //
  511. // This routine exchanges the values pointed to by pop1 and pop2. It is
  512. // understood that pop2 points to an intel register and therefore does
  513. // not require synchronized access
  514. //
  515. // Arguments:
  516. //
  517. // pop1 <a0> -- A pointer to the content of op1
  518. // pop2 <a1> -- A pointer to the content of op2
  519. //
  520. // Return Value:
  521. //
  522. // none
  523. //
  524. ITCHK_INIT
  525. //
  526. // Get op2
  527. //
  528. xchg01: ldl t1, (a1)
  529. //
  530. // get op1
  531. // store op2 into op1 (possibly memory)
  532. // if the value of op1 changed between load and store, try again
  533. //
  534. ldl_l t0, (a0)
  535. stl_c t1, (a0)
  536. beq t1, xchg02
  537. stl t0, (a1)
  538. ret zero, (ra)
  539. //
  540. // Someone else modified (or might have modified) the location
  541. // we're trying to atomically modify
  542. //
  543. xchg02: ITCHK
  544. br zero, xchg01
  545. ENDFRAGLOCK(Xchg)
  546. FRAGLOCK(Xadd)
  547. //
  548. // Routine Description:
  549. //
  550. // This routine places op1 into pop2 and op1+op2 into pop1. It is
  551. // understood that pop2 points to an intel register and therefore does
  552. // not require synchronized access
  553. //
  554. // Arguments:
  555. //
  556. // &op1 <a0> -- A place to store op1 once known
  557. // pop1 <a1> -- A pointer to the content of op1
  558. // pop2 <a2> -- A pointer to the content of op2
  559. //
  560. // Return Value:
  561. //
  562. // none
  563. //
  564. ITCHK_INIT
  565. //
  566. // Get op2
  567. //
  568. xadd01: ldl t1, (a2)
  569. //
  570. // Get op1
  571. // add op2
  572. // if the value of op1 changed between load and store, try again
  573. //
  574. ldl_l t0, (a1)
  575. addl t1, t0, t1
  576. mov t1, v0
  577. stl_c t1, (a1)
  578. beq t1, xadd02
  579. //
  580. // why do we do this???
  581. //
  582. stl t0, (a2)
  583. stl t0, (a0)
  584. ret zero, (ra)
  585. //
  586. // Someone else modified (or might have modified) the location
  587. // we're trying to atomically modify
  588. //
  589. xadd02: ITCHK
  590. br zero, xadd01
  591. ENDFRAGLOCK(Xadd)
  592. FRAGLOCK(CmpXchg)
  593. //
  594. // Routine Description:
  595. //
  596. // This routine compares the accumulator with the destination. If they
  597. // are equal, source is loaded in the destination, otherwise dest is loaded
  598. // into the accumulator. It is understood that dest is the only pointer into
  599. // intel memory.
  600. //
  601. // Arguments:
  602. //
  603. // eax <a0> -- A pointer to the accumulator
  604. // pop1 <a1> -- A pointer to the destination
  605. // pop2 <a2> -- A pointer to the source
  606. // &op1 <a3> -- A place to store op1 once known
  607. //
  608. // Return Value:
  609. //
  610. // The value to put in the zero flag
  611. //
  612. // Notes:
  613. //
  614. // 1.) On page 5-7 of Alpha Architecture Reference Manual
  615. // (ISBN 1-55558-098-X) subtlety #4, "some implementations
  616. // may not allow a successful stx_c after a branch taken."
  617. // This means that the branch between the ldl_l and the stl_c
  618. // should be not taken for the case where we want to store the
  619. // value.
  620. //
  621. ITCHK_INIT
  622. //
  623. // get source and eax
  624. //
  625. ldl t0, (a0)
  626. cx10: ldl t2, (a2)
  627. //
  628. // Get destination
  629. //
  630. ldl_l t1, (a1)
  631. //
  632. // check for d == eax
  633. // (can we use some of the cmove instructions here?)
  634. //
  635. cmpeq t1, t0, t3
  636. beq t3, cx20
  637. //
  638. // They're equal so copy source to dest, set return value
  639. //
  640. stl_c t2, (a1)
  641. beq t2, cx30
  642. addl zero, zero, v0
  643. stl t1, (a3)
  644. ret zero, (ra)
  645. //
  646. // Not equal, store dest in eax, set return value
  647. //
  648. cx20: stl t1, (a0)
  649. stl t1, (a3)
  650. addl zero, 1, v0
  651. ret zero, (ra)
  652. //
  653. // Someone else modified (or might have modified) the location
  654. // we're trying to atomically modify
  655. //
  656. cx30: ITCHK
  657. br zero, cx10
  658. ENDFRAGLOCK(CmpXchg)
  659. FRAGLOCK(CmpXchg8b)
  660. //
  661. // Routine Description:
  662. //
  663. // This routine compares the accumulator with the destination. If they
  664. // are equal, source is loaded in the destination, otherwise dest is loaded
  665. // into the accumulator. It is understood that dest is the only pointer into
  666. // intel memory.
  667. //
  668. // Arguments:
  669. //
  670. // eax <a0> -- A pointer to the value of edx:eax
  671. // pop1 <a1> -- A pointer to the value of ecx:ebx
  672. // pop2 <a2> -- A pointer to the memory value
  673. //
  674. // Return Value:
  675. //
  676. // The value to put in the zero flag
  677. //
  678. // Notes:
  679. //
  680. // 1.) On page 5-7 of Alpha Architecture Reference Manual
  681. // (ISBN 1-55558-098-X) subtlety #4, "some implementations
  682. // may not allow a successful stx_c after a branch taken."
  683. // This means that the branch between the ldl_l and the stl_c
  684. // should be not taken for the case where we want to store the
  685. // value.
  686. //
  687. ITCHK_INIT
  688. //
  689. // get source and eax
  690. //
  691. ldq t0, (a0) // t0 = value of EDX:EAX
  692. cxb10: ldq t1, (a1) // t1 = value of ECX:EBX
  693. //
  694. // Get destination
  695. //
  696. ldq_l t2, (a2) // t2 = value of memory
  697. //
  698. // check for d == edx:eax
  699. // (can we use some of the cmove instructions here?)
  700. //
  701. cmpeq t0, t2, t3
  702. beq t3, cxb20
  703. //
  704. // They're equal so copy source to dest, set return value
  705. //
  706. stq_c t1, (a2)
  707. beq t1, cxb30
  708. addl zero, zero, v0
  709. ret zero, (ra)
  710. //
  711. // Not equal, store dest in edx:eax, set return value
  712. //
  713. cxb20: stl t2, (a0) // update edx:eax
  714. addl zero, 1, v0
  715. ret zero, (ra)
  716. //
  717. // Someone else modified (or might have modified) the location
  718. // we're trying to atomically modify
  719. //
  720. cxb30: ITCHK
  721. br zero, cxb10
  722. ENDFRAGLOCK(CmpXchg8b)