contextc.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. /*++
  2. Copyright (c) 2016 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. contextc.c
  9. Abstract:
  10. This module implements C support for working with ucontext structures in
  11. the C library.
  12. Author:
  13. Evan Green 8-Sep-2016
  14. Environment:
  15. User Mode C Library
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #include "../libcp.h"
  21. #include <alloca.h>
  22. #include <errno.h>
  23. #include <signal.h>
  24. #include <ucontext.h>
  25. #include <minoca/kernel/x86.h>
  26. //
  27. // ---------------------------------------------------------------- Definitions
  28. //
  29. //
  30. // ------------------------------------------------------ Data Type Definitions
  31. //
  32. //
  33. // ----------------------------------------------- Internal Function Prototypes
  34. //
  35. __NO_RETURN
  36. VOID
  37. ClpContextEnd (
  38. ucontext_t *Context
  39. );
  40. __NO_RETURN
  41. void
  42. ClpContextStart (
  43. void (*StartFunction)(),
  44. ...
  45. );
  46. VOID
  47. ClpFxSave (
  48. PFPU_CONTEXT Buffer
  49. );
  50. VOID
  51. ClpFxRestore (
  52. PFPU_CONTEXT Buffer
  53. );
  54. VOID
  55. ClpFSave (
  56. PFPU_CONTEXT Buffer
  57. );
  58. VOID
  59. ClpFRestore (
  60. PFPU_CONTEXT Buffer
  61. );
  62. //
  63. // -------------------------------------------------------------------- Globals
  64. //
  65. //
  66. // ------------------------------------------------------------------ Functions
  67. //
  68. LIBC_API
  69. void
  70. makecontext (
  71. ucontext_t *Context,
  72. void (*StartFunction)(),
  73. int ArgumentCount,
  74. ...
  75. )
  76. /*++
  77. Routine Description:
  78. This routine modifies an initialized context to call the function provided
  79. with the given arguments.
  80. Arguments:
  81. Context - Supplies a pointer to the context.
  82. StartFunction - Supplies a pointer to the function to call when the
  83. context is restored.
  84. ArgumentCount - Supplies the number of int sized arguments supplied.
  85. ... - Supplies the remaining arguments to pass to the function.
  86. Return Value:
  87. None.
  88. --*/
  89. {
  90. PUINTN Argument;
  91. va_list ArgumentList;
  92. UINTN Index;
  93. PVOID StackTop;
  94. PTRAP_FRAME TrapFrame;
  95. if (Context == NULL) {
  96. return;
  97. }
  98. //
  99. // Create a stack that looks like this (starting with the last pushed):
  100. // ClpContextStart
  101. // StartFunction
  102. // Argument1 (16 byte aligned)
  103. // ...
  104. // ArgumentN
  105. // Context.
  106. //
  107. StackTop = (PVOID)(Context->uc_stack.ss_sp + Context->uc_stack.ss_size -
  108. sizeof(UINTN));
  109. StackTop -= (ArgumentCount + 1) * sizeof(UINTN);
  110. StackTop = ALIGN_POINTER_DOWN(StackTop, 16);
  111. StackTop -= 2 * sizeof(UINTN);
  112. Argument = (PUINTN)StackTop;
  113. *Argument = (UINTN)ClpContextStart;
  114. Argument += 1;
  115. *Argument = (UINTN)StartFunction;
  116. Argument += 1;
  117. va_start(ArgumentList, ArgumentCount);
  118. for (Index = 0; Index < ArgumentCount; Index += 1) {
  119. *Argument = va_arg(ArgumentList, UINTN);
  120. Argument += 1;
  121. }
  122. va_end(ArgumentList);
  123. *Argument = (UINTN)Context;
  124. //
  125. // Set the registers to point at the top of the stack.
  126. //
  127. TrapFrame = (PTRAP_FRAME)&(Context->uc_mcontext.gregs);
  128. TrapFrame->Esi = (UINTN)Argument;
  129. TrapFrame->Ebp = 0;
  130. TrapFrame->Esp = (UINTN)StackTop + sizeof(PVOID);
  131. TrapFrame->Eip = (UINTN)ClpContextStart;
  132. return;
  133. }
  134. int
  135. ClpGetContext (
  136. ucontext_t *Context,
  137. void *StackPointer
  138. )
  139. /*++
  140. Routine Description:
  141. This routine stores the current FPU and general context into the given
  142. structure. The assembly code that calls this routine is responsible for
  143. saving the general registers.
  144. Arguments:
  145. Context - Supplies a pointer to the context.
  146. StackPointer - Supplies the current stack pointer.
  147. Return Value:
  148. 0 on success.
  149. -1 on failure, and errno will be set to contain more information.
  150. --*/
  151. {
  152. BOOL Aligned;
  153. int Error;
  154. PFPU_CONTEXT FpuContext;
  155. void *StackBase;
  156. size_t StackSize;
  157. pthread_attr_t ThreadAttribute;
  158. Error = pthread_getattr_np(pthread_self(), &ThreadAttribute);
  159. if (Error != 0) {
  160. errno = Error;
  161. return -1;
  162. }
  163. Error = pthread_attr_getstack(&ThreadAttribute, &StackBase, &StackSize);
  164. if (Error != 0) {
  165. errno = Error;
  166. return -1;
  167. }
  168. if (StackBase == NULL) {
  169. StackBase = StackPointer;
  170. }
  171. Context->uc_flags = SIGNAL_CONTEXT_FLAG_FPU_VALID;
  172. Context->uc_stack.ss_sp = StackPointer;
  173. Context->uc_stack.ss_flags = 0;
  174. Context->uc_stack.ss_size = StackSize;
  175. //
  176. // TODO: Enable this when sigaltstack is implemented.
  177. //
  178. #if 0
  179. //
  180. // If currently on the signal stack, then the thread parameters aren't
  181. // correct.
  182. //
  183. if (sigaltstack(NULL, &SignalStack) == 0) {
  184. if ((SignalStack.ss_flags & SS_ONSTACK) != 0) {
  185. Context->uc_stack = SignalStack;
  186. }
  187. }
  188. #endif
  189. sigprocmask(0, NULL, &(Context->uc_sigmask));
  190. //
  191. // Get the FPU context buffer. If it's not aligned, it will have to be
  192. // saved into an aligned buffer and then copied.
  193. //
  194. Aligned = IS_POINTER_ALIGNED(&(Context->uc_mcontext.fpregs),
  195. __FPSTATE_ALIGNMENT);
  196. if (Aligned != FALSE) {
  197. FpuContext = (PFPU_CONTEXT)&(Context->uc_mcontext.fpregs);
  198. } else {
  199. FpuContext = alloca(__FPSTATE_SIZE + __FPSTATE_ALIGNMENT);
  200. FpuContext = ALIGN_POINTER_UP(FpuContext, __FPSTATE_ALIGNMENT);
  201. }
  202. //
  203. // Save the floating point state.
  204. //
  205. if (OsTestProcessorFeature(OsX86FxSave) != FALSE) {
  206. ClpFxSave(FpuContext);
  207. } else {
  208. ClpFSave(FpuContext);
  209. }
  210. if (FpuContext != (PFPU_CONTEXT)&(Context->uc_mcontext.fpregs)) {
  211. memcpy(&(Context->uc_mcontext.fpregs),
  212. FpuContext,
  213. sizeof(Context->uc_mcontext.fpregs));
  214. }
  215. pthread_attr_destroy(&ThreadAttribute);
  216. return 0;
  217. }
  218. void
  219. ClpSetContext (
  220. const ucontext_t *Context
  221. )
  222. /*++
  223. Routine Description:
  224. This routine restores the user context set in the given structure.
  225. Arguments:
  226. Context - Supplies a pointer to the context.
  227. Return Value:
  228. None.
  229. --*/
  230. {
  231. PFPU_CONTEXT FpuContext;
  232. //
  233. // Restore the floating point context using the appropriate mechanism.
  234. //
  235. if ((Context->uc_flags & SIGNAL_CONTEXT_FLAG_FPU_VALID) != 0) {
  236. //
  237. // If the structure causes the floating point context not to be aligned,
  238. // allocate a temporary structure, align it, and copy the data in.
  239. //
  240. FpuContext = (PFPU_CONTEXT)&(Context->uc_mcontext.fpregs);
  241. if (!IS_POINTER_ALIGNED(FpuContext, __FPSTATE_ALIGNMENT)) {
  242. FpuContext = alloca(__FPSTATE_SIZE + __FPSTATE_ALIGNMENT);
  243. FpuContext = ALIGN_POINTER_UP(FpuContext, __FPSTATE_ALIGNMENT);
  244. memcpy(FpuContext,
  245. &(Context->uc_mcontext.fpregs),
  246. sizeof(FPU_CONTEXT));
  247. }
  248. if (OsTestProcessorFeature(OsX86FxSave) != FALSE) {
  249. ClpFxRestore(FpuContext);
  250. } else {
  251. ClpFRestore(FpuContext);
  252. }
  253. }
  254. sigprocmask(SIG_SETMASK, &(Context->uc_sigmask), NULL);
  255. return;
  256. }
  257. //
  258. // --------------------------------------------------------- Internal Functions
  259. //