diff --git a/arch/arm/include/arm/irq.h b/arch/arm/include/arm/irq.h index 11c2bb0463..98335c23f5 100644 --- a/arch/arm/include/arm/irq.h +++ b/arch/arm/include/arm/irq.h @@ -103,6 +103,12 @@ #define REG_LR REG_R14 #define REG_PC REG_R15 +/* The PIC register is usually R10. It can be R9 is stack checking is enabled + * or if the user changes it with -mpic-register on the GCC command line. + */ + +#define REG_PIC REG_R10 + /**************************************************************************** * Public Types ****************************************************************************/ diff --git a/arch/arm/include/cortexm3/irq.h b/arch/arm/include/cortexm3/irq.h index ce126748a6..b439ec42fa 100644 --- a/arch/arm/include/cortexm3/irq.h +++ b/arch/arm/include/cortexm3/irq.h @@ -109,6 +109,12 @@ #define REG_LR REG_R14 #define REG_PC REG_R15 +/* The PIC register is usually R10. It can be R9 is stack checking is enabled + * or if the user changes it with -mpic-register on the GCC command line. + */ + +#define REG_PIC REG_R10 + /**************************************************************************** * Public Types ****************************************************************************/ diff --git a/arch/arm/src/arm/up_initialstate.c b/arch/arm/src/arm/up_initialstate.c index 2ba6834454..c3a5f8a83f 100644 --- a/arch/arm/src/arm/up_initialstate.c +++ b/arch/arm/src/arm/up_initialstate.c @@ -93,6 +93,21 @@ void up_initial_state(_TCB *tcb) xcp->regs[REG_PC] = (uint32)tcb->start; + /* If this task is running PIC, then set the PIC base register to the + * address of the allocated D-Space region. + */ + +#ifdef CONFIG_PIC + if (tcb->dspace != NULL) + { + /* Set the PIC base register (probably R10) to the address of the + * alloacated D-Space region. + */ + + xcp->regs[REG_PIC] = (uint32)tcb->dspace->region; + } +#endif + /* Enable or disable interrupts, based on user configuration */ # ifdef CONFIG_SUPPRESS_INTERRUPTS diff --git a/arch/arm/src/cortexm3/up_initialstate.c b/arch/arm/src/cortexm3/up_initialstate.c index c529064d46..9bf65bf57a 100644 --- a/arch/arm/src/cortexm3/up_initialstate.c +++ b/arch/arm/src/cortexm3/up_initialstate.c @@ -97,6 +97,21 @@ void up_initial_state(_TCB *tcb) xcp->regs[REG_XPSR] = CORTEXM3_XPSR_T; + /* If this task is running PIC, then set the PIC base register to the + * address of the allocated D-Space region. + */ + +#ifdef CONFIG_PIC + if (tcb->dspace != NULL) + { + /* Set the PIC base register (probably R10) to the address of the + * alloacated D-Space region. + */ + + xcp->regs[REG_PIC] = (uint32)tcb->dspace->region; + } +#endif + /* Enable or disable interrupts, based on user configuration */ # ifdef CONFIG_SUPPRESS_INTERRUPTS diff --git a/binfmt/binfmt_execmodule.c b/binfmt/binfmt_execmodule.c index de65c15cf2..21fe559874 100644 --- a/binfmt/binfmt_execmodule.c +++ b/binfmt/binfmt_execmodule.c @@ -145,7 +145,7 @@ int exec_module(FAR const struct binary_s *bin, int priority) /* Add the DSpace address as the PIC base address */ #ifdef CONFIG_PIC - tcb->picbase = bin->dspace; + tcb->dspace = bin->dspace; /* Re-initialize the task's initial state to account for the new PIC base */ diff --git a/binfmt/libnxflat/libnxflat_load.c b/binfmt/libnxflat/libnxflat_load.c index aa00f50c75..b27dca9356 100644 --- a/binfmt/libnxflat/libnxflat_load.c +++ b/binfmt/libnxflat/libnxflat_load.c @@ -118,7 +118,7 @@ static void nxflat_reloc(struct nxflat_loadinfo_s *loadinfo, uint32 rl) * DSpace to hold information needed by ld.so at run time. */ - datastart = loadinfo->dspace; + datastart = (uint32)loadinfo->dspace->region; /* Get a pointer to the value that needs relocation in * DSpace. @@ -257,22 +257,22 @@ int nxflat_load(struct nxflat_loadinfo_s *loadinfo) * uninitialized ISpace memory. */ - loadinfo->dspace = (uint32)malloc(loadinfo->dsize); + loadinfo->dspace = (struct dspace_s *)malloc(SIZEOF_DSPACE_S(loadinfo->dsize)); if (loadinfo->dspace == 0) { bdbg("Failed to allocate DSpace\n"); ret = -ENOMEM; goto errout; } + loadinfo->dspace->crefs = 1; - bvdbg("Allocated DSpace (%d bytes) at %08x\n", - loadinfo->dsize, loadinfo->dspace); + bvdbg("Allocated DSpace (%d bytes) at %p\n", loadinfo->dsize, loadinfo->dspace); /* Now, read the data into allocated DSpace at doffset into the * allocated DSpace memory. */ - ret = nxflat_read(loadinfo, (char*)loadinfo->dspace, dreadsize, doffset); + ret = nxflat_read(loadinfo, (char*)loadinfo->dspace->region, dreadsize, doffset); if (ret < 0) { bdbg("Failed to read .data section: %d\n", ret); @@ -285,10 +285,10 @@ int nxflat_load(struct nxflat_loadinfo_s *loadinfo) /* Resolve the address of the relocation table. In the file, the * relocations should lie at the same offset as BSS. The current * value of relocstart is the offset from the beginning of the file. - * The following adjustment will convert it to an address in DSpace. + * The following adjustment will convert it to an address in dspace-> */ - reloctab = (uint32*)(loadinfo->relocstart + loadinfo->dspace - loadinfo->isize); + reloctab = (uint32*)(loadinfo->relocstart + (uint32)loadinfo->dspace->region - loadinfo->isize); bvdbg("Relocation table at 0x%p, reloccount=%d\n", reloctab, loadinfo->reloccount); @@ -304,7 +304,7 @@ int nxflat_load(struct nxflat_loadinfo_s *loadinfo) * in the file. */ - memset((void*)(loadinfo->dspace + loadinfo->datasize), + memset((void*)(loadinfo->dspace->region + loadinfo->datasize), 0, loadinfo->bsssize); return OK; diff --git a/examples/nxflat/tests/Make.defs b/examples/nxflat/tests/Make.defs index c4ec82c52a..3b6400730e 100644 --- a/examples/nxflat/tests/Make.defs +++ b/examples/nxflat/tests/Make.defs @@ -41,5 +41,5 @@ NXFLATCC = $(CC) NXFLATCFLAGS = $(CFLAGS) NXFLATLD = $(LD) -NXFLATLDFLAGS = +NXFLATLDFLAGS = -e main diff --git a/include/nuttx/binfmt.h b/include/nuttx/binfmt.h index 855cc3359f..0c4238989d 100644 --- a/include/nuttx/binfmt.h +++ b/include/nuttx/binfmt.h @@ -43,6 +43,7 @@ #include #include #include +#include /**************************************************************************** * Pre-processor Definitions @@ -65,7 +66,7 @@ struct binary_s main_t entrypt; /* Entry point into a program module */ FAR void *ispace; /* Memory-mapped, I-space (.text) address */ - FAR void *dspace; /* Address of the allocated .data/.bss space */ + FAR struct dspace_s *dspace; /* Address of the allocated .data/.bss space */ size_t isize; /* Size of the I-space region (needed for munmap) */ size_t stacksize; /* Size of the stack in bytes (unallocated) */ }; diff --git a/include/nuttx/nxflat.h b/include/nuttx/nxflat.h index f78c79dcd4..543f00e6d3 100644 --- a/include/nuttx/nxflat.h +++ b/include/nuttx/nxflat.h @@ -40,7 +40,9 @@ * Included Files ****************************************************************************/ +#include #include +#include /**************************************************************************** * Pre-processor Definitions @@ -61,29 +63,29 @@ struct nxflat_loadinfo_s * text section instance in the system for each module. */ - uint32 ispace; /* Address where hdr/text is loaded */ - uint32 entryoffs; /* Offset from ispace to entry point */ - uint32 isize; /* Size of ispace. */ + uint32 ispace; /* Address where hdr/text is loaded */ + uint32 entryoffs; /* Offset from ispace to entry point */ + uint32 isize; /* Size of ispace. */ /* Data Space (DSpace): This region contains all information that in referenced * as data (other than the stack which is separately allocated). There will be * a unique instance of DSpace (and stack) for each instance of a process. */ - uint32 dspace; /* Address where data/bss/etc. is loaded */ - uint32 datasize; /* Size of data segment in dspace */ - uint32 bsssize; /* Size of bss segment in dspace */ - uint32 stacksize; /* Size of stack (not allocated) */ - uint32 dsize; /* Size of dspace (may be large than parts) */ + struct dspace_s *dspace; /* Allocated D-Space (data/bss/etc) */ + uint32 datasize; /* Size of data segment in dspace */ + uint32 bsssize; /* Size of bss segment in dspace */ + uint32 stacksize; /* Size of stack (not allocated) */ + uint32 dsize; /* Size of dspace (may be large than parts) */ /* This is temporary memory where relocation records will be loaded. */ - uint32 relocstart; /* Start of array of struct flat_reloc */ - uint32 reloccount; /* Number of elements in reloc array */ + uint32 relocstart; /* Start of array of struct flat_reloc */ + uint32 reloccount; /* Number of elements in reloc array */ /* File descriptors */ - int filfd; /* Descriptor for the file being loaded */ + int filfd; /* Descriptor for the file being loaded */ const struct nxflat_hdr_s *header; /* A reference to the flat file header */ }; diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h index 520d73047d..0c55dc1f87 100644 --- a/include/nuttx/sched.h +++ b/include/nuttx/sched.h @@ -161,6 +161,18 @@ typedef struct environ_s environ_t; # define SIZEOF_ENVIRON_T(alloc) (sizeof(environ_t) + alloc - 1) #endif +/* This structure describes a reference counted D-Space region */ + +struct dspace_s +{ + uint32 crefs; /* This is the number of pthreads that shared the + * the same D-Space. + */ + ubyte region[1]; /* Beginning of the allocated region */ +}; + +#define SIZEOF_DSPACE_S(n) (sizeof(struct dspace_s) - 1 + (n)) + /* This is the task control block (TCB) */ struct _TCB @@ -217,7 +229,7 @@ struct _TCB /* External Module Support ****************************************************/ #ifdef CONFIG_PIC - FAR void *picbase; /* Allocated area for .bss and .data */ + FAR struct dspace_s *dspace; /* Allocated area for .bss and .data */ #endif /* POSIX Thread Specific Data *************************************************/ diff --git a/sched/sched_releasetcb.c b/sched/sched_releasetcb.c index 567db20211..cd8e9c8c32 100644 --- a/sched/sched_releasetcb.c +++ b/sched/sched_releasetcb.c @@ -138,9 +138,16 @@ int sched_releasetcb(FAR _TCB *tcb) /* Delete the tasks's allocated DSpace region (external modules only) */ #ifdef CONFIG_PIC - if (tcb->picbase) + if (tcb->dspace) { - sched_free(tcb->picbase); + if (tcb->dspace->crefs <= 1) + { + sched_free(tcb->dspace); + } + else + { + tcb->dspace->crefs--; + } } #endif diff --git a/sched/task_setup.c b/sched/task_setup.c index 25a85394a9..83bae570b1 100644 --- a/sched/task_setup.c +++ b/sched/task_setup.c @@ -142,6 +142,43 @@ static STATUS task_assignpid(FAR _TCB *tcb) return ERROR; } +/**************************************************************************** + * Function: task_dupdspace + * + * Description: + * When a new task or thread is created from a PIC module, then that + * module (probably) intends the task or thread to execute in the same + * D-Space. This function will duplicate the D-Space for that purpose. + * + * Parameters: + * tcb - The TCB of the new task. + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_PIC +static inline void task_dupdspace(FAR _TCB *tcb) +{ + FAR _TCB *rtcb = (FAR _TCB*)g_readytorun.head; + if (rtcb->dspace != NULL) + { + /* Copy the D-Space structure reference and increment the reference + * count on the memory. The D-Space memory will persist until the + * last thread exits (see sched_releasetcb()). + */ + + tcb->dspace = rtcb->dspace; + tcb->dspace->crefs++; + } +} +#else +# define task_dupdspace(tcb) +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -150,11 +187,11 @@ static STATUS task_assignpid(FAR _TCB *tcb) * Name: task_schedsetup * * Description: - * This functions initializes a Task Control Block (TCB) - * in preparation for starting a new thread. + * This functions initializes a Task Control Block (TCB) in preparation + * for starting a new thread. * - * task_schedsetup() is called from task_init(), - * task_start(), and pthread_create(); + * task_schedsetup() is called from task_init(), task_start(), and + * pthread_create(); * * Input Parameters: * tcb - Address of the new task's TCB @@ -165,8 +202,8 @@ static STATUS task_assignpid(FAR _TCB *tcb) * Return Value: * OK on success; ERROR on failure. * - * This function can only failure is it is unable to assign - * a new, unique task ID to the TCB (errno is not set). + * This function can only failure is it is unable to assign a new, unique + * task ID to the TCB (errno is not set). * ****************************************************************************/ @@ -204,6 +241,13 @@ STATUS task_schedsetup(FAR _TCB *tcb, int priority, tcb->task_state = TSTATE_TASK_INVALID; + /* Clone the parent tasks D-Space (if it was running PIC). This + * must be done before calling up_initial_state() so that the + * state setup will take the PIC address base into account. + */ + + task_dupdspace(tcb); + /* Initialize the processor-specific portion of the TCB */ up_initial_state(tcb); diff --git a/sched/wd_start.c b/sched/wd_start.c index ea9117459b..a406b3f30c 100644 --- a/sched/wd_start.c +++ b/sched/wd_start.c @@ -158,9 +158,7 @@ STATUS wd_start(WDOG_ID wdog, int delay, wdentry_t wdentry, int argc, ...) /* Save the data in the watchdog structure */ wdog->func = wdentry; /* Function to execute when delay expires */ -#ifdef CONFIG_PIC up_getpicbase(&wdog->picbase); -#endif wdog->argc = argc; va_start(ap, argc);