contextc.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  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 9-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/x64.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. //
  55. // -------------------------------------------------------------------- Globals
  56. //
  57. //
  58. // ------------------------------------------------------------------ Functions
  59. //
  60. //
  61. // TODO: Test these ucontext routines once x64 is running.
  62. //
  63. LIBC_API
  64. void
  65. makecontext (
  66. ucontext_t *Context,
  67. void (*StartFunction)(),
  68. int ArgumentCount,
  69. ...
  70. )
  71. /*++
  72. Routine Description:
  73. This routine modifies an initialized context to call the function provided
  74. with the given arguments.
  75. Arguments:
  76. Context - Supplies a pointer to the context.
  77. StartFunction - Supplies a pointer to the function to call when the
  78. context is restored.
  79. ArgumentCount - Supplies the number of int sized arguments supplied.
  80. ... - Supplies the remaining arguments to pass to the function.
  81. Return Value:
  82. None.
  83. --*/
  84. {
  85. PUINTN Argument;
  86. va_list ArgumentList;
  87. UINTN Index;
  88. UINTN Minimum;
  89. PVOID StackTop;
  90. PTRAP_FRAME TrapFrame;
  91. if (Context == NULL) {
  92. return;
  93. }
  94. //
  95. // Create a stack that looks like this (starting with the last pushed):
  96. // ClpContextStart
  97. // StartFunction
  98. // Argument1 (16 byte aligned)
  99. // ...
  100. // ArgumentN
  101. // Context.
  102. //
  103. StackTop = (PVOID)(Context->uc_stack.ss_sp + Context->uc_stack.ss_size -
  104. sizeof(UINTN));
  105. //
  106. // At a minimum, push arguments to account for all the register passed
  107. // arguments.
  108. //
  109. Minimum = 6;
  110. if (ArgumentCount > Minimum) {
  111. Minimum = ArgumentCount;
  112. }
  113. StackTop -= (Minimum + 1) * sizeof(UINTN);
  114. StackTop = ALIGN_POINTER_DOWN(StackTop, 16);
  115. StackTop -= 2 * sizeof(UINTN);
  116. Argument = (PUINTN)StackTop;
  117. *Argument = (UINTN)ClpContextStart;
  118. Argument += 1;
  119. *Argument = (UINTN)StartFunction;
  120. Argument += 1;
  121. va_start(ArgumentList, ArgumentCount);
  122. for (Index = 0; Index < ArgumentCount; Index += 1) {
  123. *Argument = va_arg(ArgumentList, UINTN);
  124. Argument += 1;
  125. }
  126. va_end(ArgumentList);
  127. //
  128. // If there are fewer argumens than passed via register, pad it out.
  129. //
  130. while (Index < Minimum) {
  131. *Argument = 0;
  132. Argument += 1;
  133. Index += 1;
  134. }
  135. //
  136. // Make sure the stack is aligned.
  137. //
  138. if ((Index & 0x1) != 0) {
  139. *Argument = 0;
  140. Argument += 1;
  141. }
  142. *Argument = (UINTN)Context;
  143. //
  144. // Set the registers to point at the top of the stack.
  145. //
  146. TrapFrame = (PTRAP_FRAME)&(Context->uc_mcontext.gregs);
  147. TrapFrame->R12 = (UINTN)Argument;
  148. TrapFrame->Rbp = 0;
  149. TrapFrame->Rsp = (UINTN)StackTop + sizeof(PVOID);
  150. TrapFrame->Rip = (UINTN)ClpContextStart;
  151. return;
  152. }
  153. int
  154. ClpGetContext (
  155. ucontext_t *Context,
  156. void *StackPointer
  157. )
  158. /*++
  159. Routine Description:
  160. This routine stores the current FPU and general context into the given
  161. structure. The assembly code that calls this routine is responsible for
  162. saving the general registers.
  163. Arguments:
  164. Context - Supplies a pointer to the context.
  165. StackPointer - Supplies the current stack pointer.
  166. Return Value:
  167. 0 on success.
  168. -1 on failure, and errno will be set to contain more information.
  169. --*/
  170. {
  171. BOOL Aligned;
  172. int Error;
  173. PFPU_CONTEXT FpuContext;
  174. void *StackBase;
  175. size_t StackSize;
  176. pthread_attr_t ThreadAttribute;
  177. Error = pthread_getattr_np(pthread_self(), &ThreadAttribute);
  178. if (Error != 0) {
  179. errno = Error;
  180. return -1;
  181. }
  182. Error = pthread_attr_getstack(&ThreadAttribute, &StackBase, &StackSize);
  183. if (Error != 0) {
  184. errno = Error;
  185. return -1;
  186. }
  187. if (StackBase == NULL) {
  188. StackBase = StackPointer;
  189. }
  190. Context->uc_flags = SIGNAL_CONTEXT_FLAG_FPU_VALID;
  191. Context->uc_stack.ss_sp = StackPointer;
  192. Context->uc_stack.ss_flags = 0;
  193. Context->uc_stack.ss_size = StackSize;
  194. //
  195. // TODO: Enable this when sigaltstack is implemented.
  196. //
  197. #if 0
  198. //
  199. // If currently on the signal stack, then the thread parameters aren't
  200. // correct.
  201. //
  202. if (sigaltstack(NULL, &SignalStack) == 0) {
  203. if ((SignalStack.ss_flags & SS_ONSTACK) != 0) {
  204. Context->uc_stack = SignalStack;
  205. }
  206. }
  207. #endif
  208. sigprocmask(0, NULL, &(Context->uc_sigmask));
  209. //
  210. // Get the FPU context buffer. If it's not aligned, it will have to be
  211. // saved into an aligned buffer and then copied.
  212. //
  213. Aligned = IS_POINTER_ALIGNED(&(Context->uc_mcontext.fpregs),
  214. __FPSTATE_ALIGNMENT);
  215. if (Aligned != FALSE) {
  216. FpuContext = (PFPU_CONTEXT)&(Context->uc_mcontext.fpregs);
  217. } else {
  218. FpuContext = alloca(__FPSTATE_SIZE + __FPSTATE_ALIGNMENT);
  219. FpuContext = ALIGN_POINTER_UP(FpuContext, __FPSTATE_ALIGNMENT);
  220. }
  221. //
  222. // Save the floating point state.
  223. //
  224. ClpFxSave(FpuContext);
  225. if (FpuContext != (PFPU_CONTEXT)&(Context->uc_mcontext.fpregs)) {
  226. memcpy(&(Context->uc_mcontext.fpregs),
  227. FpuContext,
  228. sizeof(Context->uc_mcontext.fpregs));
  229. }
  230. pthread_attr_destroy(&ThreadAttribute);
  231. return 0;
  232. }
  233. void
  234. ClpSetContext (
  235. const ucontext_t *Context
  236. )
  237. /*++
  238. Routine Description:
  239. This routine restores the user context set in the given structure.
  240. Arguments:
  241. Context - Supplies a pointer to the context.
  242. Return Value:
  243. None.
  244. --*/
  245. {
  246. PFPU_CONTEXT FpuContext;
  247. //
  248. // If the structure causes the floating point context not to be aligned,
  249. // allocate a temporary structure, align it, and copy the data in.
  250. //
  251. if ((Context->uc_flags & SIGNAL_CONTEXT_FLAG_FPU_VALID) != 0) {
  252. FpuContext = (PFPU_CONTEXT)&(Context->uc_mcontext.fpregs);
  253. if (!IS_POINTER_ALIGNED(FpuContext, __FPSTATE_ALIGNMENT)) {
  254. FpuContext = alloca(__FPSTATE_SIZE + __FPSTATE_ALIGNMENT);
  255. FpuContext = ALIGN_POINTER_UP(FpuContext, __FPSTATE_ALIGNMENT);
  256. memcpy(FpuContext,
  257. &(Context->uc_mcontext.fpregs),
  258. sizeof(FPU_CONTEXT));
  259. }
  260. //
  261. // Restore the floating point context using the appropriate mechanism.
  262. //
  263. ClpFxRestore(FpuContext);
  264. }
  265. sigprocmask(SIG_SETMASK, &(Context->uc_sigmask), NULL);
  266. return;
  267. }
  268. //
  269. // --------------------------------------------------------- Internal Functions
  270. //