ksr1.h 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /*
  2. * QuickThreads -- Threads-building toolkit.
  3. * Copyright (c) 1993 by David Keppel
  4. *
  5. * Permission to use, copy, modify and distribute this software and
  6. * its documentation for any purpose and without fee is hereby
  7. * granted, provided that the above copyright notice and this notice
  8. * appear in all copies. This software is provided as a
  9. * proof-of-concept and for demonstration purposes; there is no
  10. * representation about the suitability of this software for any
  11. * purpose.
  12. */
  13. #ifndef QT_KSR1_H
  14. #define QT_KSR1_H
  15. /*
  16. Stack layout:
  17. Registers are saved in strictly low to high order, FPU regs first
  18. (only if qt_block is called), CEU regs second, IPU regs next, with no
  19. padding between the groups.
  20. Callee-save: f16..f63; c15..c30; i12..i30.
  21. Args passed in i2..i5.
  22. Note: c31 is a private data pointer. It is not changed on thread
  23. swaps with the assumption that it represents per-processor rather
  24. than per-thread state.
  25. Note: i31 is an instruction count register that is updated by the
  26. context switch routines. Like c31, it is not changed on context
  27. switches.
  28. This is what we want on startup:
  29. +------ <-- BOS: Bottom of stack (grows down)
  30. | 80 (128 - 48) bytes of padding to a 128-byte boundary
  31. +---
  32. | only
  33. | userf
  34. | t
  35. | u
  36. | qt_start$TXT
  37. | (empty) <-- qt.sp
  38. +------ <-- (BOS - 128)
  39. This is why we want this on startup:
  40. A thread begins running when the restore procedure switches thread stacks
  41. and pops a return address off of the top of the new stack (see below
  42. for the reason why we explicitly store qt_start$TXT). The
  43. block procedure pushes two jump addresses on a thread's stack before
  44. it switches stacks. The first is the return address for the block
  45. procedure, and the second is a restore address. The return address
  46. is used to jump back to the thread that has been switched to; the
  47. restore address is a jump within the block code to restore the registers.
  48. Normally, this is just a jump to the next address. However, on thread
  49. startup, this is a jump to qt_start$TXT. (The block procedure stores
  50. the restore address at an offset of 8 bytes from the top of the stack,
  51. which is also the offset at which qt_start$TXT is stored on the stacks
  52. of new threads. Hence, when the block procedure switches to a new
  53. thread stack, it will initially jump to qt_start$TXT; thereafter,
  54. it jumps to the restore code.)
  55. qt_start$TXT, after it has read the initial data on the new thread's
  56. stack and placed it in registers, pops the initial stack frame
  57. and gives the thread the entire stack to use for execution.
  58. The KSR runtime system has an unusual treatment of pointers to
  59. functions. From C, taking the `name' of a function yields a
  60. pointer to a _constant block_ and *not* the address of the
  61. function. The zero'th entry in the constant block is a pointer to
  62. the function.
  63. We have to be careful: the restore procedure expects a return
  64. address on the top of the stack (pointed to by qt.sp). This is not
  65. a problem when restoring a thread that has run before, since the
  66. block routine would have stored the return address on top of the
  67. stack. However, when ``faking up'' a thread start (bootstrapping a
  68. thread stack frame), the top of the stack needs to contain a
  69. pointer to the code that will start the thread running.
  70. The pointer to the startup code is *not* `qt_start'. It is the
  71. word *pointed to* by `qt_start'. Thus, we dereference `qt_start',
  72. see QT_ARGS_MD below.
  73. On varargs startup (still unimplemented):
  74. | padding to 128 byte boundary
  75. | varargs <-- padded to a 128-byte-boundary
  76. +---
  77. | caller's frame, 16 bytes
  78. | 80 bytes of padding (frame padded to a 128-byte boundary)
  79. +---
  80. | cleanup
  81. | vuserf
  82. | startup
  83. | t
  84. +---
  85. | qt_start <-- qt.sp
  86. +---
  87. Of a suspended thread:
  88. +---
  89. | caller's frame, 16 bytes
  90. | fpu registers 47 regs * 8 bytes/reg 376 bytes
  91. | ceu registers 16 regs * 8 bytes/reg 128 bytes
  92. | ipu registers 19 regs * 8 bytes/reg 152 bytes
  93. | :
  94. | 80 bytes of padding
  95. | :
  96. | qt_restore <-- qt.sp
  97. +---
  98. */
  99. #define QT_STKALIGN 128
  100. #define QT_GROW_DOWN
  101. typedef unsigned long qt_word_t;
  102. #define QT_STKBASE QT_STKALIGN
  103. #define QT_VSTKBASE QT_STKBASE
  104. extern void qt_start(void);
  105. /*
  106. * See the discussion above for what indexing into a procedure ptr
  107. * does for us (it's lovely, though, isn't it?).
  108. *
  109. * This assumes that the address of a procedure's code is the
  110. * first word in a procedure's constant block. That's how the manual
  111. * says it will be arranged.
  112. */
  113. #define QT_ARGS_MD(sp) (QT_SPUT (sp, 1, ((qt_word_t *)qt_start)[0]))
  114. /*
  115. * The *index* (positive offset) of where to put each value.
  116. * See the picture of the stack above that explains the offsets.
  117. */
  118. #define QT_ONLY_INDEX (5)
  119. #define QT_USER_INDEX (4)
  120. #define QT_ARGT_INDEX (3)
  121. #define QT_ARGU_INDEX (2)
  122. #define QT_VARGS_DEFAULT
  123. #define QT_VARGS(sp, nb, vargs, pt, startup, vuserf, cleanup) \
  124. (qt_vargs (sp, nbytes, &vargs, pt, startup, vuserf, cleanup))
  125. #define QT_VARGS_MD0(sp, vabytes) \
  126. ((qt_t *)(((char *)(sp)) - 4*8 - QT_STKROUNDUP(vabytes)))
  127. extern void qt_vstart(void);
  128. #define QT_VARGS_MD1(sp) (QT_SPUT (sp, 0, ((qt_word_t *)qt_vstart)[0]))
  129. #define QT_VCLEANUP_INDEX (4)
  130. #define QT_VUSERF_INDEX (3)
  131. #define QT_VSTARTUP_INDEX (2)
  132. #define QT_VARGT_INDEX (1)
  133. #endif /* def QT_KSR1_H */