binfmt_execmodule.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /****************************************************************************
  2. * binfmt/binfmt_execmodule.c
  3. *
  4. * Licensed to the Apache Software Foundation (ASF) under one or more
  5. * contributor license agreements. See the NOTICE file distributed with
  6. * this work for additional information regarding copyright ownership. The
  7. * ASF licenses this file to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance with the
  9. * License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  15. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  16. * License for the specific language governing permissions and limitations
  17. * under the License.
  18. *
  19. ****************************************************************************/
  20. /****************************************************************************
  21. * Included Files
  22. ****************************************************************************/
  23. #include <nuttx/config.h>
  24. #include <sys/types.h>
  25. #include <stdint.h>
  26. #include <stdlib.h>
  27. #include <sched.h>
  28. #include <debug.h>
  29. #include <errno.h>
  30. #include <nuttx/arch.h>
  31. #include <nuttx/kmalloc.h>
  32. #include <nuttx/sched.h>
  33. #include <nuttx/mm/shm.h>
  34. #include <nuttx/binfmt/binfmt.h>
  35. #include "binfmt.h"
  36. #ifndef CONFIG_BINFMT_DISABLE
  37. /****************************************************************************
  38. * Pre-processor Definitions
  39. ****************************************************************************/
  40. /* If C++ constructors are used, then CONFIG_SCHED_STARTHOOK must also be
  41. * selected be the start hook is used to schedule execution of the
  42. * constructors.
  43. */
  44. #if defined(CONFIG_BINFMT_CONSTRUCTORS) && !defined(CONFIG_SCHED_STARTHOOK)
  45. # error "CONFIG_SCHED_STARTHOOK must be defined to use constructors"
  46. #endif
  47. /****************************************************************************
  48. * Private Functions
  49. ****************************************************************************/
  50. /****************************************************************************
  51. * Name: exec_ctors
  52. *
  53. * Description:
  54. * Execute C++ static constructors. This function is registered as a
  55. * start hook and runs on the thread of the newly created task before
  56. * the new task's main function is called.
  57. *
  58. * Input Parameters:
  59. * arg - Argument is instance of load state info structure cast to void *.
  60. *
  61. * Returned Value:
  62. * 0 (OK) is returned on success and a negated errno is returned on
  63. * failure.
  64. *
  65. ****************************************************************************/
  66. #ifdef CONFIG_BINFMT_CONSTRUCTORS
  67. static void exec_ctors(FAR void *arg)
  68. {
  69. FAR const struct binary_s *binp = (FAR const struct binary_s *)arg;
  70. binfmt_ctor_t *ctor = binp->ctors;
  71. int i;
  72. /* Execute each constructor */
  73. for (i = 0; i < binp->nctors; i++)
  74. {
  75. binfo("Calling ctor %d at %p\n", i, (FAR void *)ctor);
  76. (*ctor)();
  77. ctor++;
  78. }
  79. }
  80. #endif
  81. /****************************************************************************
  82. * Public Functions
  83. ****************************************************************************/
  84. /****************************************************************************
  85. * Name: exec_module
  86. *
  87. * Description:
  88. * Execute a module that has been loaded into memory by load_module().
  89. *
  90. * Returned Value:
  91. * This is a NuttX internal function so it follows the convention that
  92. * 0 (OK) is returned on success and a negated errno is returned on
  93. * failure.
  94. *
  95. ****************************************************************************/
  96. int exec_module(FAR const struct binary_s *binp)
  97. {
  98. FAR struct task_tcb_s *tcb;
  99. #if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
  100. save_addrenv_t oldenv;
  101. #endif
  102. pid_t pid;
  103. int ret;
  104. /* Sanity checking */
  105. #ifdef CONFIG_DEBUG_FEATURES
  106. if (!binp || !binp->entrypt || binp->stacksize <= 0)
  107. {
  108. return -EINVAL;
  109. }
  110. #endif
  111. binfo("Executing %s\n", binp->filename);
  112. /* Allocate a TCB for the new task. */
  113. tcb = (FAR struct task_tcb_s *)kmm_zalloc(sizeof(struct task_tcb_s));
  114. if (!tcb)
  115. {
  116. return -ENOMEM;
  117. }
  118. #if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
  119. /* Instantiate the address environment containing the user heap */
  120. ret = up_addrenv_select(&binp->addrenv, &oldenv);
  121. if (ret < 0)
  122. {
  123. berr("ERROR: up_addrenv_select() failed: %d\n", ret);
  124. goto errout_with_tcb;
  125. }
  126. #endif
  127. /* Note that tcb->flags are not modified. 0=normal task */
  128. /* tcb->flags |= TCB_FLAG_TTYPE_TASK; */
  129. /* Initialize the task */
  130. ret = nxtask_init(tcb, binp->filename, binp->priority,
  131. NULL, binp->stacksize, binp->entrypt, binp->argv);
  132. if (ret < 0)
  133. {
  134. berr("nxtask_init() failed: %d\n", ret);
  135. goto errout_with_addrenv;
  136. }
  137. /* We can free the argument buffer now.
  138. * REVISIT: It is good to free up memory as soon as possible, but
  139. * unfortunately here 'binp' is 'const'. So to do this properly, we will
  140. * have to make some more extensive changes.
  141. */
  142. binfmt_freeargv((FAR struct binary_s *)binp);
  143. #if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
  144. /* Allocate the kernel stack */
  145. ret = up_addrenv_kstackalloc(&tcb->cmn);
  146. if (ret < 0)
  147. {
  148. berr("ERROR: up_addrenv_kstackalloc() failed: %d\n", ret);
  149. goto errout_with_tcbinit;
  150. }
  151. #endif
  152. #ifdef CONFIG_MM_SHM
  153. /* Initialize the shared memory virtual page allocator */
  154. ret = shm_group_initialize(tcb->cmn.group);
  155. if (ret < 0)
  156. {
  157. berr("ERROR: shm_group_initialize() failed: %d\n", ret);
  158. goto errout_with_tcbinit;
  159. }
  160. #endif
  161. #ifdef CONFIG_PIC
  162. /* Add the D-Space address as the PIC base address. By convention, this
  163. * must be the first allocated address space.
  164. */
  165. tcb->cmn.dspace = binp->alloc[0];
  166. /* Re-initialize the task's initial state to account for the new PIC base */
  167. up_initial_state(&tcb->cmn);
  168. #endif
  169. #ifdef CONFIG_ARCH_ADDRENV
  170. /* Assign the address environment to the new task group */
  171. ret = up_addrenv_clone(&binp->addrenv, &tcb->cmn.group->tg_addrenv);
  172. if (ret < 0)
  173. {
  174. berr("ERROR: up_addrenv_clone() failed: %d\n", ret);
  175. goto errout_with_tcbinit;
  176. }
  177. /* Mark that this group has an address environment */
  178. tcb->cmn.group->tg_flags |= GROUP_FLAG_ADDRENV;
  179. #endif
  180. #ifdef CONFIG_BINFMT_CONSTRUCTORS
  181. /* Setup a start hook that will execute all of the C++ static constructors
  182. * on the newly created thread. The struct binary_s must persist at least
  183. * until the new task has been started.
  184. */
  185. if (binp->nctors > 0)
  186. {
  187. nxtask_starthook(tcb, exec_ctors, (FAR void *)binp);
  188. }
  189. #endif
  190. /* Get the assigned pid before we start the task */
  191. pid = tcb->cmn.pid;
  192. /* Then activate the task at the provided priority */
  193. nxtask_activate((FAR struct tcb_s *)tcb);
  194. #if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
  195. /* Restore the address environment of the caller */
  196. ret = up_addrenv_restore(&oldenv);
  197. if (ret < 0)
  198. {
  199. berr("ERROR: up_addrenv_restore() failed: %d\n", ret);
  200. goto errout_with_tcbinit;
  201. }
  202. #endif
  203. return (int)pid;
  204. #if defined(CONFIG_ARCH_ADDRENV) || defined(CONFIG_MM_SHM)
  205. errout_with_tcbinit:
  206. tcb->cmn.stack_alloc_ptr = NULL;
  207. nxsched_release_tcb(&tcb->cmn, TCB_FLAG_TTYPE_TASK);
  208. return ret;
  209. #endif
  210. errout_with_addrenv:
  211. #if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
  212. up_addrenv_restore(&oldenv);
  213. errout_with_tcb:
  214. #endif
  215. kmm_free(tcb);
  216. return ret;
  217. }
  218. #endif /* CONFIG_BINFMT_DISABLE */