binfmt_execmodule.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /****************************************************************************
  2. * binfmt/binfmt_execmodule.c
  3. *
  4. * Copyright (C) 2009, 2013-2014, 2017 Gregory Nutt. All rights reserved.
  5. * Author: Gregory Nutt <gnutt@nuttx.org>
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in
  15. * the documentation and/or other materials provided with the
  16. * distribution.
  17. * 3. Neither the name NuttX nor the names of its contributors may be
  18. * used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  29. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. * POSSIBILITY OF SUCH DAMAGE.
  33. *
  34. ****************************************************************************/
  35. /****************************************************************************
  36. * Included Files
  37. ****************************************************************************/
  38. #include <nuttx/config.h>
  39. #include <sys/types.h>
  40. #include <stdint.h>
  41. #include <stdlib.h>
  42. #include <sched.h>
  43. #include <debug.h>
  44. #include <errno.h>
  45. #include <nuttx/arch.h>
  46. #include <nuttx/kmalloc.h>
  47. #include <nuttx/mm/shm.h>
  48. #include <nuttx/binfmt/binfmt.h>
  49. #include "sched/sched.h"
  50. #include "binfmt.h"
  51. #ifndef CONFIG_BINFMT_DISABLE
  52. /****************************************************************************
  53. * Pre-processor Definitions
  54. ****************************************************************************/
  55. /* If C++ constructors are used, then CONFIG_SCHED_STARTHOOK must also be
  56. * selected be the start hook is used to schedule execution of the
  57. * constructors.
  58. */
  59. #if defined(CONFIG_BINFMT_CONSTRUCTORS) && !defined(CONFIG_SCHED_STARTHOOK)
  60. # errror "CONFIG_SCHED_STARTHOOK must be defined to use constructors"
  61. #endif
  62. /****************************************************************************
  63. * Private Functions
  64. ****************************************************************************/
  65. /****************************************************************************
  66. * Name: exec_ctors
  67. *
  68. * Description:
  69. * Execute C++ static constructors. This function is registered as a
  70. * start hook and runs on the thread of the newly created task before
  71. * the new task's main function is called.
  72. *
  73. * Input Parameters:
  74. * arg - Argument is instance of load state info structure cast to void *.
  75. *
  76. * Returned Value:
  77. * 0 (OK) is returned on success and a negated errno is returned on
  78. * failure.
  79. *
  80. ****************************************************************************/
  81. #ifdef CONFIG_BINFMT_CONSTRUCTORS
  82. static void exec_ctors(FAR void *arg)
  83. {
  84. FAR const struct binary_s *binp = (FAR const struct binary_s *)arg;
  85. binfmt_ctor_t *ctor = binp->ctors;
  86. int i;
  87. /* Execute each constructor */
  88. for (i = 0; i < binp->nctors; i++)
  89. {
  90. binfo("Calling ctor %d at %p\n", i, (FAR void *)ctor);
  91. (*ctor)();
  92. ctor++;
  93. }
  94. }
  95. #endif
  96. /****************************************************************************
  97. * Public Functions
  98. ****************************************************************************/
  99. /****************************************************************************
  100. * Name: exec_module
  101. *
  102. * Description:
  103. * Execute a module that has been loaded into memory by load_module().
  104. *
  105. * Returned Value:
  106. * This is a NuttX internal function so it follows the convention that
  107. * 0 (OK) is returned on success and a negated errno is returned on
  108. * failure.
  109. *
  110. ****************************************************************************/
  111. int exec_module(FAR const struct binary_s *binp)
  112. {
  113. FAR struct task_tcb_s *tcb;
  114. #if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
  115. save_addrenv_t oldenv;
  116. #endif
  117. FAR uint32_t *stack;
  118. pid_t pid;
  119. int ret;
  120. /* Sanity checking */
  121. #ifdef CONFIG_DEBUG_FEATURES
  122. if (!binp || !binp->entrypt || binp->stacksize <= 0)
  123. {
  124. return -EINVAL;
  125. }
  126. #endif
  127. binfo("Executing %s\n", binp->filename);
  128. /* Allocate a TCB for the new task. */
  129. tcb = (FAR struct task_tcb_s *)kmm_zalloc(sizeof(struct task_tcb_s));
  130. if (!tcb)
  131. {
  132. return -ENOMEM;
  133. }
  134. #if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
  135. /* Instantiate the address environment containing the user heap */
  136. ret = up_addrenv_select(&binp->addrenv, &oldenv);
  137. if (ret < 0)
  138. {
  139. berr("ERROR: up_addrenv_select() failed: %d\n", ret);
  140. goto errout_with_tcb;
  141. }
  142. #endif
  143. /* Allocate the stack for the new task.
  144. *
  145. * REVISIT: This allocation is currently always from the user heap. That
  146. * will need to change if/when we want to support dynamic stack allocation.
  147. */
  148. stack = (FAR uint32_t *)kumm_malloc(binp->stacksize);
  149. if (!stack)
  150. {
  151. ret = -ENOMEM;
  152. goto errout_with_addrenv;
  153. }
  154. /* Initialize the task */
  155. ret = task_init((FAR struct tcb_s *)tcb, binp->filename, binp->priority,
  156. stack, binp->stacksize, binp->entrypt, binp->argv);
  157. if (ret < 0)
  158. {
  159. ret = -get_errno();
  160. berr("task_init() failed: %d\n", ret);
  161. goto errout_with_addrenv;
  162. }
  163. /* We can free the argument buffer now.
  164. * REVISIT: It is good to free up memory as soon as possible, but
  165. * unfortunately here 'binp' is 'const'. So to do this properly, we will
  166. * have to make some more extensive changes.
  167. */
  168. binfmt_freeargv((FAR struct binary_s *)binp);
  169. /* Note that tcb->flags are not modified. 0=normal task */
  170. /* tcb->flags |= TCB_FLAG_TTYPE_TASK; */
  171. #if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
  172. /* Allocate the kernel stack */
  173. ret = up_addrenv_kstackalloc(&tcb->cmn);
  174. if (ret < 0)
  175. {
  176. berr("ERROR: up_addrenv_select() failed: %d\n", ret);
  177. goto errout_with_tcbinit;
  178. }
  179. #endif
  180. #if defined(CONFIG_BUILD_KERNEL) && defined(CONFIG_MM_SHM)
  181. /* Initialize the shared memory virtual page allocator */
  182. ret = shm_group_initialize(tcb->cmn.group);
  183. if (ret < 0)
  184. {
  185. berr("ERROR: shm_group_initialize() failed: %d\n", ret);
  186. goto errout_with_tcbinit;
  187. }
  188. #endif
  189. #ifdef CONFIG_PIC
  190. /* Add the D-Space address as the PIC base address. By convention, this
  191. * must be the first allocated address space.
  192. */
  193. tcb->cmn.dspace = binp->alloc[0];
  194. /* Re-initialize the task's initial state to account for the new PIC base */
  195. up_initial_state(&tcb->cmn);
  196. #endif
  197. #ifdef CONFIG_ARCH_ADDRENV
  198. /* Assign the address environment to the new task group */
  199. ret = up_addrenv_clone(&binp->addrenv, &tcb->cmn.group->tg_addrenv);
  200. if (ret < 0)
  201. {
  202. berr("ERROR: up_addrenv_clone() failed: %d\n", ret);
  203. goto errout_with_tcbinit;
  204. }
  205. /* Mark that this group has an address environment */
  206. tcb->cmn.group->tg_flags |= GROUP_FLAG_ADDRENV;
  207. #endif
  208. #ifdef CONFIG_BINFMT_CONSTRUCTORS
  209. /* Setup a start hook that will execute all of the C++ static constructors
  210. * on the newly created thread. The struct binary_s must persist at least
  211. * until the new task has been started.
  212. */
  213. if (binp->nctors > 0)
  214. {
  215. nxtask_starthook(tcb, exec_ctors, (FAR void *)binp);
  216. }
  217. #endif
  218. /* Get the assigned pid before we start the task */
  219. pid = tcb->cmn.pid;
  220. /* Then activate the task at the provided priority */
  221. ret = task_activate((FAR struct tcb_s *)tcb);
  222. if (ret < 0)
  223. {
  224. ret = -get_errno();
  225. berr("task_activate() failed: %d\n", ret);
  226. goto errout_with_tcbinit;
  227. }
  228. #if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
  229. /* Restore the address environment of the caller */
  230. ret = up_addrenv_restore(&oldenv);
  231. if (ret < 0)
  232. {
  233. berr("ERROR: up_addrenv_select() failed: %d\n", ret);
  234. goto errout_with_tcbinit;
  235. }
  236. #endif
  237. return (int)pid;
  238. errout_with_tcbinit:
  239. tcb->cmn.stack_alloc_ptr = NULL;
  240. sched_releasetcb(&tcb->cmn, TCB_FLAG_TTYPE_TASK);
  241. kumm_free(stack);
  242. return ret;
  243. errout_with_addrenv:
  244. #if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
  245. (void)up_addrenv_restore(&oldenv);
  246. errout_with_tcb:
  247. #endif
  248. kmm_free(tcb);
  249. return ret;
  250. }
  251. #endif /* CONFIG_BINFMT_DISABLE */