_sparc.s 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /* sparc.s -- assembly support for the `qt' thread building kit. */
  2. /*
  3. * QuickThreads -- Threads-building toolkit.
  4. * Copyright (c) 1993 by David Keppel
  5. *
  6. * Permission to use, copy, modify and distribute this software and
  7. * its documentation for any purpose and without fee is hereby
  8. * granted, provided that the above copyright notice and this notice
  9. * appear in all copies. This software is provided as a
  10. * proof-of-concept and for demonstration purposes; there is no
  11. * representation about the suitability of this software for any
  12. * purpose.
  13. */
  14. /* #include <machine/trap.h> */
  15. .text
  16. .align 4
  17. .global _qt_blocki
  18. .global _qt_block
  19. .global _qt_abort
  20. .global _qt_start
  21. .global _qt_vstart
  22. /* Register assignment:
  23. // %o0: incoming `helper' function to call after cswap
  24. // also used as outgoing sp of old thread (qt_t *)
  25. // %o1, %o2:
  26. // parameters to `helper' function called after cswap
  27. // %o3: sp of new thread
  28. // %o5: tmp used to save old thread sp, while using %o0
  29. // to call `helper' f() after cswap.
  30. //
  31. //
  32. // Aborting a thread is easy if there are no cached register window
  33. // frames: just switch to the new stack and away we go. If there are
  34. // cached register window frames they must all be written back to the
  35. // old stack before we move to the new stack. If we fail to do the
  36. // writeback then the old stack memory can be written with register
  37. // window contents e.g., after the stack memory has been freed and
  38. // reused.
  39. //
  40. // If you don't believe this, try setting the frame pointer to zero
  41. // once we're on the new stack. This will not affect correctnes
  42. // otherwise because the frame pointer will eventually get reloaded w/
  43. // the new thread's frame pointer. But it will be zero briefly before
  44. // the reload. You will eventually (100,000 cswaps later on a small
  45. // SPARC machine that I tried) get an illegal instruction trap from
  46. // the kernel trying to flush a cached window to location 0x0.
  47. //
  48. // Solution: flush windows before switching stacks, which invalidates
  49. // all the other register windows. We could do the trap
  50. // conditionally: if we're in the lowest frame of a thread, the fp is
  51. // zero already so we know there's nothing cached. But we expect most
  52. // aborts will be done from a first function that does a `save', so we
  53. // will rarely save anything and always pay the cost of testing to see
  54. // if we should flush.
  55. //
  56. // All floating-point registers are caller-save, so this routine
  57. // doesn't need to do anything to save and restore them.
  58. //
  59. // `qt_block' and `qt_blocki' return the same value as the value
  60. // returned by the helper function. We get this ``for free''
  61. // since we don't touch the return value register between the
  62. // return from the helper function and return from qt_block{,i}.
  63. */
  64. _qt_block:
  65. _qt_blocki:
  66. sub %sp, 8, %sp /* Allocate save area for return pc. */
  67. st %o7, [%sp+64] /* Save return pc. */
  68. _qt_abort:
  69. ta 0x03 /* Save locals and ins. */
  70. mov %sp, %o5 /* Remember old sp w/o chng ins/locals. */
  71. sub %o3, 64, %sp /* Allocate kwsa, switch stacks. */
  72. call %o0, 0 /* Call `helper' routine. */
  73. mov %o5, %o0 /* Pass old thread to qt_after_t() */
  74. /* .. along w/ args in %o1 & %o2. */
  75. /* Restore callee-save regs. The kwsa
  76. // is on this stack, so offset all
  77. // loads by sizeof(kwsa), 64 bytes.
  78. */
  79. ldd [%sp+ 0+64], %l0
  80. ldd [%sp+ 8+64], %l2
  81. ldd [%sp+16+64], %l4
  82. ldd [%sp+24+64], %l6
  83. ldd [%sp+32+64], %i0
  84. ldd [%sp+40+64], %i2
  85. ldd [%sp+48+64], %i4
  86. ldd [%sp+56+64], %i6
  87. ld [%sp+64+64], %o7 /* Restore return pc. */
  88. retl /* Return to address in %o7. */
  89. add %sp, 72, %sp /* Deallocate kwsa, ret pc area. */
  90. /* The function calling conventions say there has to be a 1-word area
  91. // in the caller's stack to hold a pointer to space for aggregate
  92. // return values. It also says there should be a 6-word area to hold
  93. // %o0..%o5 if the callee wants to save them (why? I don't know...)
  94. // Round up to 8 words to maintain alignment.
  95. //
  96. // Parameter values were stored in callee-save regs and are moved to
  97. // the parameter registers.
  98. */
  99. _qt_start:
  100. mov %i1, %o0 /* `pu': Set up args to `only'. */
  101. mov %i2, %o1 /* `pt'. */
  102. mov %i4, %o2 /* `userf'. */
  103. call %i5, 0 /* Call client function. */
  104. sub %sp, 32, %sp /* Allocate 6-word callee space. */
  105. call _qt_error, 0 /* `only' erroniously returned. */
  106. nop
  107. /* Same comments as `_qt_start' about allocating rounded-up 7-word
  108. // save areas. */
  109. _qt_vstart:
  110. sub %sp, 32, %sp /* Allocate 7-word callee space. */
  111. call %i5, 0 /* call `startup'. */
  112. mov %i2, %o0 /* .. with argument `pt'. */
  113. add %sp, 32, %sp /* Use 7-word space in varargs. */
  114. ld [%sp+ 4+64], %o0 /* Load arg0 ... */
  115. ld [%sp+ 8+64], %o1
  116. ld [%sp+12+64], %o2
  117. ld [%sp+16+64], %o3
  118. ld [%sp+20+64], %o4
  119. call %i4, 0 /* Call `userf'. */
  120. ld [%sp+24+64], %o5
  121. /* Use 6-word space in varargs. */
  122. mov %o0, %o1 /* Pass return value from userf */
  123. call %i3, 0 /* .. when call `cleanup. */
  124. mov %i2, %o0 /* .. along with argument `pt'. */
  125. call _qt_error, 0 /* `cleanup' erroniously returned. */
  126. nop