summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nuttx/ChangeLog3
-rw-r--r--nuttx/Documentation/NuttX.html4
-rw-r--r--nuttx/TODO21
-rw-r--r--nuttx/arch/arm/src/arm/vfork.S3
-rw-r--r--nuttx/arch/arm/src/armv7-m/vfork.S3
-rw-r--r--nuttx/arch/arm/src/common/up_vfork.c2
-rw-r--r--nuttx/arch/arm/src/common/up_vfork.h8
-rw-r--r--nuttx/arch/mips/Kconfig1
-rw-r--r--nuttx/arch/mips/src/mips32/Kconfig8
-rw-r--r--nuttx/arch/mips/src/mips32/up_vfork.c254
-rw-r--r--nuttx/arch/mips/src/mips32/up_vfork.h132
-rw-r--r--nuttx/arch/mips/src/mips32/vfork.S154
-rw-r--r--nuttx/arch/mips/src/pic32mx/Make.defs4
-rw-r--r--nuttx/configs/ubw32/ostest/defconfig9
-rw-r--r--nuttx/sched/task_vfork.c8
15 files changed, 599 insertions, 15 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index 41ac95db0..2d2cd8259 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -3952,4 +3952,7 @@
scripts sub-directory
* configs/ubw32/ostest: Configuration configured to use the
kconfig-frontends tools.
+ * arch/mips/src/mips32/up_vfork.c, up_vfork.h, and vfork.S:
+ Implement vfork() for MIPS32 (no floating point support)
+ * configs/ubw32/ostest: Enable the vfork() test.
diff --git a/nuttx/Documentation/NuttX.html b/nuttx/Documentation/NuttX.html
index 22651de79..c5f1ebc9c 100644
--- a/nuttx/Documentation/NuttX.html
+++ b/nuttx/Documentation/NuttX.html
@@ -381,7 +381,7 @@
<td><br></td>
<td>
<p>
- <li>Well documented in the NuttX <a href="NuttXUserGuide.html">User Guide</a>.</li>
+ <li>Well documented in the NuttX <a href="NuttxUserGuide.html">User Guide</a>.</li>
</p>
</tr>
@@ -3833,7 +3833,7 @@ pascal-3.0 2011-05-15 Gregory Nutt &lt;gnutt@nuttx.org&gt;
</tr>
<tr>
<td valign="top" width="22"><img height="20" width="20" src="favicon.ico"></td>
- <td><a href="NuttXUserGuide.html">User Guide</a></td>
+ <td><a href="NuttxUserGuide.html">User Guide</a></td>
</tr>
<tr>
<td valign="top" width="22"><img height="20" width="20" src="favicon.ico"></td>
diff --git a/nuttx/TODO b/nuttx/TODO
index 0d02e10e6..58ca4cc8e 100644
--- a/nuttx/TODO
+++ b/nuttx/TODO
@@ -6,7 +6,7 @@ standards, things that could be improved, and ideas for enhancements.
nuttx/
- (10) Task/Scheduler (sched/)
+ (11) Task/Scheduler (sched/)
(1) Memory Managment (mm/)
(3) Signals (sched/, arch/)
(2) pthreads (sched/)
@@ -195,6 +195,25 @@ o Task/Scheduler (sched/)
Status: Open
Priority: Low
+ Title: IMPROVED TASK CONTROL BLOCK STRUCTURE
+ All task resources that are shared amongst threads have
+ their own "break-away", reference-counted structure. The
+ Task Control Block (TCB) of each thread holds a reference
+ to each breakaway structure (see include/nuttx/sched.h).
+ It would be more efficent to have one reference counted
+ structure that holds all of the shared resources.
+
+ These are the current shared structures:
+ - Environment varaibles (struct environ_s)
+ - PIC data space and address environments (struct dspace_s)
+ - File descriptors (struct filelist)
+ - FILE streams (struct streamlist)
+ - Sockets (struct socketlist)
+ Status: Open
+ Priority: Low. This is an enhancement. It would slight reduce
+ memory usage but would also increase coupling. These
+ resources are nicely modular now.
+
o Memory Managment (mm/)
^^^^^^^^^^^^^^^^^^^^^^
diff --git a/nuttx/arch/arm/src/arm/vfork.S b/nuttx/arch/arm/src/arm/vfork.S
index 226d9f7de..7c3c8b727 100644
--- a/nuttx/arch/arm/src/arm/vfork.S
+++ b/nuttx/arch/arm/src/arm/vfork.S
@@ -105,6 +105,7 @@ vfork:
mov r0, sp /* Save the value of the stack on entry */
sub sp, sp, #VFORK_SIZEOF /* Allocate the structure on the stack */
+ /* CPU registers */
/* Save the volatile registers */
str r4, [sp, #VFORK_R4_OFFSET]
@@ -121,6 +122,8 @@ vfork:
str r0, [sp, #VFORK_SP_OFFSET]
str lr, [sp, #VFORK_LR_OFFSET]
+ /* Floating point registers (not yet) */
+
/* Then, call up_vfork(), passing it a pointer to the stack structure */
mov r0, sp
diff --git a/nuttx/arch/arm/src/armv7-m/vfork.S b/nuttx/arch/arm/src/armv7-m/vfork.S
index 386fca33c..f36ff23aa 100644
--- a/nuttx/arch/arm/src/armv7-m/vfork.S
+++ b/nuttx/arch/arm/src/armv7-m/vfork.S
@@ -108,6 +108,7 @@ vfork:
mov r0, sp /* Save the value of the stack on entry */
sub sp, sp, #VFORK_SIZEOF /* Allocate the structure on the stack */
+ /* CPU registers */
/* Save the volatile registers */
str r4, [sp, #VFORK_R4_OFFSET]
@@ -124,6 +125,8 @@ vfork:
str r0, [sp, #VFORK_SP_OFFSET]
str lr, [sp, #VFORK_LR_OFFSET]
+ /* Floating point registers (not yet) */
+
/* Then, call up_vfork(), passing it a pointer to the stack structure */
mov r0, sp
diff --git a/nuttx/arch/arm/src/common/up_vfork.c b/nuttx/arch/arm/src/common/up_vfork.c
index 5349378bc..3b653e317 100644
--- a/nuttx/arch/arm/src/common/up_vfork.c
+++ b/nuttx/arch/arm/src/common/up_vfork.c
@@ -208,7 +208,7 @@ pid_t up_vfork(const struct vfork_s *context)
svdbg("New stack base:%08x SP:%08x FP:%08x\n",
child->adj_stack_ptr, newsp, newfp);
- /* Update the stack pointer, frame pointer, and voltile registers. When
+ /* Update the stack pointer, frame pointer, and volatile registers. When
* the child TCB was initialized, all of the values were set to zero.
* up_initial_state() altered a few values, but the return value in R0
* should be cleared to zero, providing the indication to the newly started
diff --git a/nuttx/arch/arm/src/common/up_vfork.h b/nuttx/arch/arm/src/common/up_vfork.h
index a4505474a..97edf9aaa 100644
--- a/nuttx/arch/arm/src/common/up_vfork.h
+++ b/nuttx/arch/arm/src/common/up_vfork.h
@@ -1,5 +1,5 @@
/****************************************************************************
- * arch/arm/src/common/arm-vfork.h
+ * arch/arm/src/common/up_vfork.h
*
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
@@ -53,6 +53,7 @@
#define VFORK_R8_OFFSET (4*4) /* Volatile register r8 */
#define VFORK_R9_OFFSET (5*4) /* Volatile register r9 */
#define VFORK_R10_OFFSET (6*4) /* Volatile register r10 */
+
#define VFORK_FP_OFFSET (7*4) /* Frame pointer */
#define VFORK_SP_OFFSET (8*4) /* Stack pointer*/
#define VFORK_LR_OFFSET (9*4) /* Return address*/
@@ -66,6 +67,8 @@
#ifndef __ASSEMBLY__
struct vfork_s
{
+ /* CPU registers */
+
uint32_t r4; /* Volatile register r4 */
uint32_t r5; /* Volatile register r5 */
uint32_t r6; /* Volatile register r6 */
@@ -73,9 +76,12 @@ struct vfork_s
uint32_t r8; /* Volatile register r8 */
uint32_t r9; /* Volatile register r9 */
uint32_t r10; /* Volatile register r10 */
+
uint32_t fp; /* Frame pointer */
uint32_t sp; /* Stack pointer*/
uint32_t lr; /* Return address*/
+
+ /* Floating point registers (not yet) */
};
#endif
diff --git a/nuttx/arch/mips/Kconfig b/nuttx/arch/mips/Kconfig
index 1b10e26ae..86482ef7a 100644
--- a/nuttx/arch/mips/Kconfig
+++ b/nuttx/arch/mips/Kconfig
@@ -22,6 +22,7 @@ endchoice
config ARCH_MIPS32
bool
default n
+ select ARCH_HAVE_VFORK
config ARCH_FAMILY
string
diff --git a/nuttx/arch/mips/src/mips32/Kconfig b/nuttx/arch/mips/src/mips32/Kconfig
index b8b5d9b92..c7a4499c2 100644
--- a/nuttx/arch/mips/src/mips32/Kconfig
+++ b/nuttx/arch/mips/src/mips32/Kconfig
@@ -47,4 +47,12 @@ config MIPS32_TOOLCHAIN_PINGUINOL
endchoice
+config MIPS32_FRAMEPOINTER
+ bool "ABI Uses Frame Pointer"
+ default n
+ depends on ARCH_HAVE_VFORK
+ ---help---
+ Register r30 may be a frame pointer in some ABIs. Or may just be
+ saved register s8. It makes a difference for vfork handling.
+
endif
diff --git a/nuttx/arch/mips/src/mips32/up_vfork.c b/nuttx/arch/mips/src/mips32/up_vfork.c
new file mode 100644
index 000000000..6b7e27f31
--- /dev/null
+++ b/nuttx/arch/mips/src/mips32/up_vfork.c
@@ -0,0 +1,254 @@
+/****************************************************************************
+ * arch/mips/src/mips32/up_vfork.c
+ *
+ * Copyright (C) 2013 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/sched.h>
+#include <nuttx/arch.h>
+#include <arch/irq.h>
+
+#include "up_vfork.h"
+#include "os_internal.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef CONFIG_STACK_ALIGNMENT
+# define CONFIG_STACK_ALIGNMENT 4
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_vfork
+ *
+ * Description:
+ * The vfork() function has the same effect as fork(), except that the
+ * behavior is undefined if the process created by vfork() either modifies
+ * any data other than a variable of type pid_t used to store the return
+ * value from vfork(), or returns from the function in which vfork() was
+ * called, or calls any other function before successfully calling _exit()
+ * or one of the exec family of functions.
+ *
+ * The overall sequence is:
+ *
+ * 1) User code calls vfork(). vfork() collects context information and
+ * transfers control up up_vfork().
+ * 2) up_vfork()and calls task_vforksetup().
+ * 3) task_vforksetup() allocates and configures the child task's TCB. This
+ * consists of:
+ * - Allocation of the child task's TCB.
+ * - Initialization of file descriptors and streams
+ * - Configuration of environment variables
+ * - Setup the intput parameters for the task.
+ * - Initialization of the TCB (including call to up_initial_state()
+ * 4) up_vfork() provides any additional operating context. up_vfork must:
+ * - Allocate and initialize the stack
+ * - Initialize special values in any CPU registers that were not
+ * already configured by up_initial_state()
+ * 5) up_vfork() then calls task_vforkstart()
+ * 6) task_vforkstart() then executes the child thread.
+ *
+ * task_vforkabort() may be called if an error occurs between steps 3 and 6.
+ *
+ * Input Paremeters:
+ * context - Caller context information saved by vfork()
+ *
+ * Return:
+ * Upon successful completion, vfork() returns 0 to the child process and
+ * returns the process ID of the child process to the parent process.
+ * Otherwise, -1 is returned to the parent, no child process is created,
+ * and errno is set to indicate the error.
+ *
+ ****************************************************************************/
+
+pid_t up_vfork(const struct vfork_s *context)
+{
+ _TCB *parent = (FAR _TCB *)g_readytorun.head;
+ _TCB *child;
+ size_t stacksize;
+ uint32_t newsp;
+#if CONFIG_MIPS32_FRAMEPOINTER
+ uint32_t newfp;
+#endif
+ uint32_t stackutil;
+ int ret;
+
+ svdbg("s0:%08x s1:%08x s2:%08x s3:%08x s4:%08x\n",
+ context->s0, context->s1, context->s2, context->s3, context->s4);
+#if CONFIG_MIPS32_FRAMEPOINTER
+ svdbg("s5:%08x s6:%08x s7:%08x\n",
+ context->s5, context->s6, context->s7);
+#ifdef MIPS32_SAVE_GP
+ svdbg("fp:%08x sp:%08x ra:%08x gp:%08x\n",
+ context->fp, context->sp, context->ra, context->gp);
+#else
+ svdbg("fp:%08x sp:%08x ra:%08x\n",
+ context->fp context->sp, context->ra);
+#endif
+#else
+ svdbg("s5:%08x s6:%08x s7:%08x s8:%08x\n",
+ context->s5, context->s6, context->s7, context->s8);
+#ifdef MIPS32_SAVE_GP
+ svdbg("sp:%08x ra:%08x gp:%08x\n",
+ context->sp, context->ra, context->gp);
+#else
+ svdbg("sp:%08x ra:%08x\n",
+ context->sp, context->ra);
+#endif
+#endif
+
+ /* Allocate and initialize a TCB for the child task. */
+
+ child = task_vforksetup((start_t)context->ra);
+ if (!child)
+ {
+ sdbg("task_vforksetup failed\n");
+ return (pid_t)ERROR;
+ }
+
+ svdbg("Parent=%p Child=%p\n", parent, child);
+
+ /* Get the size of the parent task's stack. Due to alignment operations,
+ * the adjusted stack size may be smaller than the stack size originally
+ * requrested.
+ */
+
+ stacksize = parent->adj_stack_size + CONFIG_STACK_ALIGNMENT - 1;
+
+ /* Allocate the stack for the TCB */
+
+ ret = up_create_stack(child, stacksize);
+ if (ret != OK)
+ {
+ sdbg("up_create_stack failed: %d\n", ret);
+ task_vforkabort(child, -ret);
+ return (pid_t)ERROR;
+ }
+
+ /* How much of the parent's stack was utilized? The MIPS uses
+ * a push-down stack so that the current stack pointer should
+ * be lower than the initial, adjusted stack pointer. The
+ * stack usage should be the difference between those two.
+ */
+
+ DEBUGASSERT((uint32_t)parent->adj_stack_ptr > context->sp);
+ stackutil = (uint32_t)parent->adj_stack_ptr - context->sp;
+
+ svdbg("stacksize:%d stackutil:%d\n", stacksize, stackutil);
+
+ /* Make some feeble effort to perserve the stack contents. This is
+ * feeble because the stack surely contains invalid pointers and other
+ * content that will not work in the child context. However, if the
+ * user follows all of the caveats of vfor() usage, even this feeble
+ * effort is overkill.
+ */
+
+ newsp = (uint32_t)child->adj_stack_ptr - stackutil;
+ memcpy((void *)newsp, (const void *)context->sp, stackutil);
+
+ /* Was there a frame pointer in place before? */
+
+#if CONFIG_MIPS32_FRAMEPOINTER
+ if (context->fp <= (uint32_t)parent->adj_stack_ptr &&
+ context->fp >= (uint32_t)parent->adj_stack_ptr - stacksize)
+ {
+ uint32_t frameutil = (uint32_t)parent->adj_stack_ptr - context->fp;
+ newfp = (uint32_t)child->adj_stack_ptr - frameutil;
+ }
+ else
+ {
+ newfp = context->fp;
+ }
+
+ svdbg("Old stack base:%08x SP:%08x FP:%08x\n",
+ parent->adj_stack_ptr, context->sp, context->fp);
+ svdbg("New stack base:%08x SP:%08x FP:%08x\n",
+ child->adj_stack_ptr, newsp, newfp);
+#else
+ svdbg("Old stack base:%08x SP:%08x\n",
+ parent->adj_stack_ptr, context->sp);
+ svdbg("New stack base:%08x SP:%08x\n",
+ child->adj_stack_ptr, newsp);
+#endif
+
+ /* Update the stack pointer, frame pointer, global pointer and saved
+ * registers. When the child TCB was initialized, all of the values
+ * were set to zero. up_initial_state() altered a few values, but the
+ * return value in v0 should be cleared to zero, providing the
+ * indication to the newly started child thread.
+ */
+
+ child->xcp.regs[REG_S0] = context->s0; /* Saved register s0 */
+ child->xcp.regs[REG_S1] = context->s1; /* Saved register s1 */
+ child->xcp.regs[REG_S2] = context->s2; /* Saved register s2 */
+ child->xcp.regs[REG_S3] = context->s3; /* Volatile register s3 */
+ child->xcp.regs[REG_S4] = context->s4; /* Volatile register s4 */
+ child->xcp.regs[REG_S5] = context->s5; /* Volatile register s5 */
+ child->xcp.regs[REG_S6] = context->s6; /* Volatile register s6 */
+ child->xcp.regs[REG_S7] = context->s7; /* Volatile register s7 */
+#if CONFIG_MIPS32_FRAMEPOINTER
+ child->xcp.regs[REG_FP] = newfp; /* Frame pointer */
+#else
+ child->xcp.regs[REG_S8] = context->s8; /* Volatile register s8 */
+#endif
+ child->xcp.regs[REG_SP] = newsp; /* Stack pointer */
+#if MIPS32_SAVE_GP
+ child->xcp.regs[REG_GP] = newsp; /* Global pointer */
+#endif
+
+ /* And, finally, start the child task. On a failure, task_vforkstart()
+ * will discard the TCB by calling task_vforkabort().
+ */
+
+ return task_vforkstart(child);
+}
diff --git a/nuttx/arch/mips/src/mips32/up_vfork.h b/nuttx/arch/mips/src/mips32/up_vfork.h
new file mode 100644
index 000000000..556633072
--- /dev/null
+++ b/nuttx/arch/mips/src/mips32/up_vfork.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+ * arch/mips/src/mips/up_vfork.h
+ *
+ * Copyright (C) 2013 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_MIPS_SRC_MIPS32_VFORK_H
+#define __ARCH_MIPS_SRC_MIPS32_VFORK_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <arch/mips32/irq.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+/* Register r30 may be a frame pointer in some ABIs. Or may just be saved
+ * register s8. It makes a difference for vfork handling.
+ */
+
+#undef VFORK_HAVE_FP
+
+/* r0 zero Always has the value 0.
+ * r1 at Temporary generally used by assembler.
+ * r2-r3 v0-v1 Used for expression evaluations and to hold the integer and
+ * pointer type function return values.
+ * r4-r7 a0-a3 Used for passing arguments to functions; values are not
+ * preserved across function calls.
+ * r8-r15 t0-t7 Temporary registers used for expression evaluation; values
+ * are not preserved across function calls.
+ * r16-r23 s0-s7 Saved registers; values are preserved across function calls.
+ * r24-r25 t8-t9 Temporary registers used for expression evaluations; values
+ * are not preserved across function calls. When calling
+ * position independent functions r25 must contain the address
+ * of the called function.
+ * r26-r27 k0-k1 Used only by the operating system.
+ * r28 gp Global pointer and context pointer.
+ * r29 sp Stack pointer.
+ * r30 s8 Saved register (like s0-s7). If a frame pointer is used,
+ * then this is the frame pointer.
+ * r31 ra Return address.
+ */
+
+#define VFORK_S0_OFFSET (0*4) /* Saved register s0 */
+#define VFORK_S1_OFFSET (1*4) /* Saved register s1 */
+#define VFORK_S2_OFFSET (2*4) /* Saved register s2 */
+#define VFORK_S3_OFFSET (3*4) /* Saved register s3 */
+#define VFORK_S4_OFFSET (4*4) /* Saved register s4 */
+#define VFORK_S5_OFFSET (5*4) /* Saved register s5 */
+#define VFORK_S6_OFFSET (6*4) /* Saved register s6 */
+#define VFORK_S7_OFFSET (7*4) /* Saved register s7 */
+
+#ifdef CONFIG_MIPS32_FRAMEPOINTER
+# define VFORK_FP_OFFSET (8*4) /* Frame pointer */
+#else
+# define VFORK_S8_OFFSET (8*4) /* Saved register s8 */
+#endif
+
+#define VFORK_SP_OFFSET (9*4) /* Stack pointer*/
+#define VFORK_RA_OFFSET (10*4) /* Return address*/
+#ifdef MIPS32_SAVE_GP
+# define VFORK_GP_OFFSET (11*4) /* Global pointer */
+# define VFORK_SIZEOF (12*4)
+#else
+# define VFORK_SIZEOF (11*4)
+#endif
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+struct vfork_s
+{
+ /* CPU registers */
+
+ uint32_t s0; /* Saved register s0 */
+ uint32_t s1; /* Saved register s1 */
+ uint32_t s2; /* Saved register s2 */
+ uint32_t s3; /* Saved register s3 */
+ uint32_t s4; /* Saved register s4 */
+ uint32_t s5; /* Saved register s5 */
+ uint32_t s6; /* Saved register s6 */
+ uint32_t s7; /* Saved register s7 */
+#ifdef CONFIG_MIPS32_FRAMEPOINTER
+ uint32_t fp; /* Frame pointer */
+#else
+ uint32_t s8; /* Saved register s8 */
+#endif
+ uint32_t sp; /* Stack pointer*/
+ uint32_t ra; /* Return address*/
+#ifdef MIPS32_SAVE_GP
+ uint32_t gp; /* Global pointer */
+#endif
+
+ /* Floating point registers (not yet) */
+};
+#endif
+
+#endif /* __ARCH_MIPS_SRC_MIPS32_VFORK_H */
diff --git a/nuttx/arch/mips/src/mips32/vfork.S b/nuttx/arch/mips/src/mips32/vfork.S
new file mode 100644
index 000000000..2b7d180d3
--- /dev/null
+++ b/nuttx/arch/mips/src/mips32/vfork.S
@@ -0,0 +1,154 @@
+/************************************************************************************
+ * arch/mips/src/mips32/vfork.S
+ *
+ * Copyright (C) 2013 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ * Included Files
+ ************************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "up_vfork.h"
+
+/************************************************************************************
+ * Pre-processor Definitions
+ ************************************************************************************/
+
+/************************************************************************************
+ * Global Symbols
+ ************************************************************************************/
+
+ .file "vfork.S"
+ .globl up_vfork
+
+/************************************************************************************
+ * Public Functions
+ ************************************************************************************/
+
+/************************************************************************************
+ * Name: vfork
+ *
+ * Description:
+ * The vfork() function has the same effect as fork(), except that the behavior is
+ * undefined if the process created by vfork() either modifies any data other than
+ * a variable of type pid_t used to store the return value from vfork(), or returns
+ * from the function in which vfork() was called, or calls any other function before
+ * successfully calling _exit() or one of the exec family of functions.
+ *
+ * This thin layer implements vfork by simply calling up_vfork() with the vfork()
+ * context as an argument. The overall sequence is:
+ *
+ * 1) User code calls vfork(). vfork() collects context information and
+ * transfers control up up_vfork().
+ * 2) up_vfork()and calls task_vforksetup().
+ * 3) task_vforksetup() allocates and configures the child task's TCB. This
+ * consists of:
+ * - Allocation of the child task's TCB.
+ * - Initialization of file descriptors and streams
+ * - Configuration of environment variables
+ * - Setup the intput parameters for the task.
+ * - Initialization of the TCB (including call to up_initial_state()
+ * 4) up_vfork() provides any additional operating context. up_vfork must:
+ * - Allocate and initialize the stack
+ * - Initialize special values in any CPU registers that were not
+ * already configured by up_initial_state()
+ * 5) up_vfork() then calls task_vforkstart()
+ * 6) task_vforkstart() then executes the child thread.
+ *
+ * Input Paremeters:
+ * None
+ *
+ * Return:
+ * Upon successful completion, vfork() returns 0 to the child process and returns
+ * the process ID of the child process to the parent process. Otherwise, -1 is
+ * returned to the parent, no child process is created, and errno is set to
+ * indicate the error.
+ *
+ ************************************************************************************/
+
+ .text
+ .align 2
+ .globl vfork
+ .type vfork, function
+ .set nomips16
+ .ent vfork
+
+vfork:
+ /* Create a stack frame */
+
+ move $t0, $sp /* Save the value of the stack on entry */
+ addiu $sp, $sp, -VFORK_SIZEOF /* Allocate the structure on the stack */
+
+ /* CPU registers */
+ /* Save the saved registers */
+
+ sw $s0, VFORK_S0_OFFSET($sp)
+ sw $s1, VFORK_S1_OFFSET($sp)
+ sw $s2, VFORK_S2_OFFSET($sp)
+ sw $s3, VFORK_S3_OFFSET($sp)
+ sw $s4, VFORK_S4_OFFSET($sp)
+ sw $s5, VFORK_S5_OFFSET($sp)
+ sw $s6, VFORK_S6_OFFSET($sp)
+ sw $s7, VFORK_S7_OFFSET($sp)
+
+#ifdef CONFIG_MIPS32_FRAMEPOINTER
+ sw $fp, VFORK_FP_OFFSET($sp)
+#else
+ sw $s8, VFORK_S8_OFFSET($sp)
+#endif
+
+ /* Save the global pointer, stack pointer, and return address */
+
+ sw $t0, VFORK_SP_OFFSET($sp)
+ sw $ra, VFORK_RA_OFFSET($sp)
+#ifdef MIPS32_SAVE_GP
+ sw $gp, VFORK_GP_OFFSET($sp)
+#endif
+
+ /* Floating point registers (not yet) */
+
+ /* Then, call up_vfork(), passing it a pointer to the stack structure */
+
+ move $a0, $sp
+ jal up_vfork
+ nop
+
+ /* Release the stack data and return the value returned by up_vfork */
+
+ lw $ra, VFORK_RA_OFFSET($sp)
+ addiu $sp, $sp, VFORK_SIZEOF
+ j $ra
+
+ .end vfork
+ .size vfork, .-vfork
diff --git a/nuttx/arch/mips/src/pic32mx/Make.defs b/nuttx/arch/mips/src/pic32mx/Make.defs
index 46fef84dc..861e1c301 100644
--- a/nuttx/arch/mips/src/pic32mx/Make.defs
+++ b/nuttx/arch/mips/src/pic32mx/Make.defs
@@ -39,14 +39,14 @@ HEAD_ASRC = pic32mx-head.S
# Common MIPS files
-CMN_ASRCS = up_syscall0.S
+CMN_ASRCS = up_syscall0.S vfork.S
CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c up_copystate.c \
up_createstack.c up_doirq.c up_exit.c up_idle.c up_initialize.c \
up_initialstate.c up_interruptcontext.c up_irq.c up_lowputs.c \
up_mdelay.c up_modifyreg8.c up_modifyreg16.c up_modifyreg32.c \
up_puts.c up_releasepending.c up_releasestack.c up_reprioritizertr.c \
up_schedulesigaction.c up_sigdeliver.c up_swint0.c up_udelay.c \
- up_unblocktask.c up_usestack.c
+ up_unblocktask.c up_usestack.c up_vfork.c
# Configuration dependent common files
diff --git a/nuttx/configs/ubw32/ostest/defconfig b/nuttx/configs/ubw32/ostest/defconfig
index 3a387ab99..a722e25e7 100644
--- a/nuttx/configs/ubw32/ostest/defconfig
+++ b/nuttx/configs/ubw32/ostest/defconfig
@@ -72,13 +72,10 @@ CONFIG_ARCH_MIPS32=y
# MIPS32 Configuration Options
#
# CONFIG_MIPS32_TOOLCHAIN_GNU_ELF is not set
-# CONFIG_MIPS32_TOOLCHAIN_MICROCHIPL is not set
-# CONFIG_MIPS32_TOOLCHAIN_MICROCHIPL_LITE is not set
# CONFIG_MIPS32_TOOLCHAIN_MICROCHIPW is not set
CONFIG_MIPS32_TOOLCHAIN_MICROCHIPW_LITE=y
-# CONFIG_MIPS32_TOOLCHAIN_MICROCHIPOPENL is not set
# CONFIG_MIPS32_TOOLCHAIN_PINGUINOW is not set
-# CONFIG_MIPS32_TOOLCHAIN_PINGUINOL is not set
+# CONFIG_MIPS32_FRAMEPOINTER is not set
#
# PIC32MX Configuration Options
@@ -245,7 +242,7 @@ CONFIG_ARCH_VECNOTIRQ=y
CONFIG_ARCH_IRQPRIO=y
# CONFIG_CUSTOM_STACK is not set
# CONFIG_ADDRENV is not set
-# CONFIG_ARCH_HAVE_VFORK is not set
+CONFIG_ARCH_HAVE_VFORK=y
CONFIG_ARCH_STACKDUMP=y
# CONFIG_ENDIAN_BIG is not set
CONFIG_ARCH_HAVE_RAMFUNCS=y
@@ -308,7 +305,7 @@ CONFIG_DEV_CONSOLE=y
# CONFIG_FDCLONE_STDIO is not set
CONFIG_SDCLONE_DISABLE=y
# CONFIG_SCHED_WORKQUEUE is not set
-# CONFIG_SCHED_WAITPID is not set
+CONFIG_SCHED_WAITPID=y
# CONFIG_SCHED_ATEXIT is not set
# CONFIG_SCHED_ONEXIT is not set
CONFIG_USER_ENTRYPOINT="ostest_main"
diff --git a/nuttx/sched/task_vfork.c b/nuttx/sched/task_vfork.c
index 4b42c7b36..46b2d8e9f 100644
--- a/nuttx/sched/task_vfork.c
+++ b/nuttx/sched/task_vfork.c
@@ -287,7 +287,11 @@ pid_t task_vforkstart(FAR _TCB *child)
#endif
#else
- /* Again exploiting that execv() bug: Check if the child thread is
+ /* The following logic does not appear to work... It gets stuff in an
+ * infinite kill() loop and hogs the processor. Therefore, it looks
+ * as though CONFIG_SCHED_WAITPID may be a requirement to used vfork().
+ *
+ * Again exploiting that execv() bug: Check if the child thread is
* still running.
*/
@@ -331,4 +335,4 @@ void task_vforkabort(FAR _TCB *child, int errcode)
sched_releasetcb(child);
set_errno(errcode);
-} \ No newline at end of file
+}