group/group_addrenv: Move address environment from group -> tcb

Detach the address environment handling from the group structure to the
tcb. This is preparation to fix rare cases where the system (MMU) is left
without a valid page directory, e.g. when a process exits.
This commit is contained in:
Ville Juven 2023-01-27 10:28:19 +02:00 committed by Xiang Xiao
parent ca95d592d3
commit 5713d85df0
34 changed files with 369 additions and 205 deletions

View File

@ -33,7 +33,6 @@
#ifndef __ASSEMBLY__
# include <stdint.h>
# include <nuttx/pgalloc.h>
# include <nuttx/addrenv.h>
#endif
/****************************************************************************

View File

@ -98,8 +98,6 @@
#include <assert.h>
#include <debug.h>
#include <nuttx/addrenv.h>
#include <nuttx/arch.h>
#include <nuttx/pgalloc.h>
#include <nuttx/irq.h>
@ -778,22 +776,18 @@ int up_addrenv_clone(const arch_addrenv_t *src,
* is created that needs to share the address environment of its task
* group.
*
* NOTE: In some platforms, nothing will need to be done in this case.
* Simply being a member of the group that has the address environment
* may be sufficient.
*
* Input Parameters:
* group - The task group to which the new thread belongs.
* tcb - The TCB of the thread needing the address environment.
* ptcb - The tcb of the parent task.
* tcb - The tcb of the thread needing the address environment.
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int up_addrenv_attach(struct task_group_s *group, struct tcb_s *tcb)
int up_addrenv_attach(struct tcb_s *ptcb, struct tcb_s *tcb)
{
binfo("group=%p tcb=%p\n", group, tcb);
binfo("parent=%p tcb=%p\n", ptcb, tcb);
/* Nothing needs to be done in this implementation */
@ -810,12 +804,7 @@ int up_addrenv_attach(struct task_group_s *group, struct tcb_s *tcb)
* task group is itself destroyed. Any resources unique to this thread
* may be destroyed now.
*
* NOTE: In some platforms, nothing will need to be done in this case.
* Simply being a member of the group that has the address environment
* may be sufficient.
*
* Input Parameters:
* group - The group to which the thread belonged.
* tcb - The TCB of the task or thread whose the address environment will
* be released.
*
@ -824,9 +813,9 @@ int up_addrenv_attach(struct task_group_s *group, struct tcb_s *tcb)
*
****************************************************************************/
int up_addrenv_detach(struct task_group_s *group, struct tcb_s *tcb)
int up_addrenv_detach(struct tcb_s *tcb)
{
binfo("group=%p tcb=%p\n", group, tcb);
binfo("tcb=%p\n", tcb);
/* Nothing needs to be done in this implementation */

View File

@ -66,7 +66,7 @@
int up_shmat(uintptr_t *pages, unsigned int npages, uintptr_t vaddr)
{
struct tcb_s *tcb = nxsched_self();
struct task_group_s *group;
struct arch_addrenv_s *addrenv;
uintptr_t *l1entry;
uint32_t *l2table;
irqstate_t flags;
@ -79,11 +79,11 @@ int up_shmat(uintptr_t *pages, unsigned int npages, uintptr_t vaddr)
/* Sanity checks */
DEBUGASSERT(pages && npages > 0 && tcb && tcb->group);
DEBUGASSERT(pages && npages > 0 && tcb && tcb->addrenv_own);
DEBUGASSERT(vaddr >= CONFIG_ARCH_SHM_VBASE && vaddr < ARCH_SHM_VEND);
DEBUGASSERT(MM_ISALIGNED(vaddr));
group = tcb->group;
addrenv = &tcb->addrenv_own->addrenv;
/* Loop until all pages have been mapped into the caller's address space. */
@ -97,7 +97,7 @@ int up_shmat(uintptr_t *pages, unsigned int npages, uintptr_t vaddr)
* address.
*/
l1entry = group->tg_addrenv.shm[shmndx];
l1entry = addrenv->shm[shmndx];
if (l1entry == NULL)
{
/* No.. Allocate one physical page for the L2 page table */
@ -115,7 +115,7 @@ int up_shmat(uintptr_t *pages, unsigned int npages, uintptr_t vaddr)
*/
flags = enter_critical_section();
group->tg_addrenv.shm[shmndx] = (uintptr_t *)paddr;
addrenv->shm[shmndx] = (uintptr_t *)paddr;
/* Get the virtual address corresponding to the physical page
* address.
@ -189,7 +189,7 @@ int up_shmat(uintptr_t *pages, unsigned int npages, uintptr_t vaddr)
int up_shmdt(uintptr_t vaddr, unsigned int npages)
{
struct tcb_s *tcb = nxsched_self();
struct task_group_s *group;
struct arch_addrenv_s *addrenv;
uintptr_t *l1entry;
uint32_t *l2table;
irqstate_t flags;
@ -201,11 +201,11 @@ int up_shmdt(uintptr_t vaddr, unsigned int npages)
/* Sanity checks */
DEBUGASSERT(npages > 0 && tcb && tcb->group);
DEBUGASSERT(npages > 0 && tcb && tcb->addrenv_own);
DEBUGASSERT(vaddr >= CONFIG_ARCH_SHM_VBASE && vaddr < ARCH_SHM_VEND);
DEBUGASSERT(MM_ISALIGNED(vaddr));
group = tcb->group;
addrenv = &tcb->addrenv_own->addrenv;
/* Loop until all pages have been unmapped from the caller's address
* space.
@ -219,7 +219,7 @@ int up_shmdt(uintptr_t vaddr, unsigned int npages)
/* Get the level 1 page table entry for this virtual address */
l1entry = group->tg_addrenv.shm[shmndx];
l1entry = addrenv->shm[shmndx];
DEBUGASSERT(l1entry != NULL);
/* Get the physical address of the L2 page table from the L1 page

View File

@ -28,13 +28,13 @@
#include <assert.h>
#include <debug.h>
#include <nuttx/addrenv.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/board.h>
#include <arch/board/board.h>
#include "arm_internal.h"
#include "group/group.h"
#include "gic.h"
/****************************************************************************
@ -85,7 +85,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
* thread at the head of the ready-to-run list.
*/
group_addrenv(NULL);
addrenv_switch(NULL);
}
#endif

View File

@ -183,16 +183,16 @@ static int get_pgtable(arch_addrenv_t *addrenv, uintptr_t vaddr)
uintptr_t pgalloc(uintptr_t brkaddr, unsigned int npages)
{
struct tcb_s *tcb = nxsched_self();
struct task_group_s *group;
struct arch_addrenv_s *addrenv;
uint32_t *l2table;
irqstate_t flags;
uintptr_t paddr;
unsigned int index;
binfo("tcb->pid=%d tcb->group=%p\n", tcb->pid, tcb->group);
binfo("tcb->pid=%d tcb->group=%p\n", tcb->pid, tcb->addrenv_own);
binfo("brkaddr=%x npages=%d\n", brkaddr, npages);
DEBUGASSERT(tcb && tcb->group);
group = tcb->group;
DEBUGASSERT(tcb && tcb->addrenv_own);
addrenv = &tcb->addrenv_own->addrenv;
/* The current implementation only supports extending the user heap
* region as part of the implementation of user sbrk(). This function
@ -200,8 +200,6 @@ uintptr_t pgalloc(uintptr_t brkaddr, unsigned int npages)
* space and (2) extending the kernel memory regions as well.
*/
DEBUGASSERT((group->tg_flags & GROUP_FLAG_ADDRENV) != 0);
/* brkaddr = 0 means that no heap has yet been allocated */
if (brkaddr == 0)
@ -216,7 +214,7 @@ uintptr_t pgalloc(uintptr_t brkaddr, unsigned int npages)
{
/* Get the physical address of the level 2 page table */
paddr = get_pgtable(&group->tg_addrenv, brkaddr);
paddr = get_pgtable(addrenv, brkaddr);
binfo("l2 page table (paddr=%x)\n", paddr);
binfo("brkaddr=%x\n", brkaddr);
if (paddr == 0)

View File

@ -31,6 +31,7 @@
#include <debug.h>
#include <syscall.h>
#include <nuttx/addrenv.h>
#include <nuttx/arch.h>
#include <nuttx/sched.h>
#include <nuttx/addrenv.h>
@ -38,7 +39,6 @@
#include "addrenv.h"
#include "arm.h"
#include "arm_internal.h"
#include "group/group.h"
#include "signal/signal.h"
/****************************************************************************
@ -596,7 +596,7 @@ uint32_t *arm_syscall(uint32_t *regs)
* thread at the head of the ready-to-run list.
*/
group_addrenv(NULL);
addrenv_switch(NULL);
}
#endif

View File

@ -33,7 +33,6 @@
#include <arch/board/board.h>
#include "arm_internal.h"
#include "group/group.h"
/****************************************************************************
* Public Functions

View File

@ -207,7 +207,7 @@ size_t up_check_tcbstack(struct tcb_s *tcb)
if ((tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_KERNEL)
{
up_addrenv_select(&tcb->group->tg_addrenv, &oldenv);
up_addrenv_select(&tcb->addrenv_own->addrenv, &oldenv);
saved = true;
}
#endif

View File

@ -824,7 +824,7 @@ int up_addrenv_clone(const arch_addrenv_t *src,
* group.
*
* Input Parameters:
* group - The task group to which the new thread belongs.
* ptcb - The tcb of the parent task.
* tcb - The tcb of the thread needing the address environment.
*
* Returned Value:
@ -832,7 +832,7 @@ int up_addrenv_clone(const arch_addrenv_t *src,
*
****************************************************************************/
int up_addrenv_attach(struct task_group_s *group, struct tcb_s *tcb)
int up_addrenv_attach(struct tcb_s *ptcb, struct tcb_s *tcb)
{
/* There is nothing that needs to be done */
@ -849,12 +849,7 @@ int up_addrenv_attach(struct task_group_s *group, struct tcb_s *tcb)
* task group is itself destroyed. Any resources unique to this thread
* may be destroyed now.
*
* NOTE: In some platforms, nothing will need to be done in this case.
* Simply being a member of the group that has the address environment
* may be sufficient.
*
* Input Parameters:
* group - The group to which the thread belonged.
* tcb - The TCB of the task or thread whose the address environment will
* be released.
*
@ -863,7 +858,7 @@ int up_addrenv_attach(struct task_group_s *group, struct tcb_s *tcb)
*
****************************************************************************/
int up_addrenv_detach(struct task_group_s *group, struct tcb_s *tcb)
int up_addrenv_detach(struct tcb_s *tcb)
{
/* There is nothing that needs to be done */

View File

@ -66,21 +66,21 @@
int up_shmat(uintptr_t *pages, unsigned int npages, uintptr_t vaddr)
{
struct tcb_s *tcb = nxsched_self();
struct task_group_s *group;
uintptr_t ptlast;
uintptr_t ptlevel;
uintptr_t paddr;
struct tcb_s *tcb = nxsched_self();
struct arch_addrenv_s *addrenv;
uintptr_t ptlast;
uintptr_t ptlevel;
uintptr_t paddr;
/* Sanity checks */
DEBUGASSERT(tcb && tcb->group);
DEBUGASSERT(tcb && tcb->addrenv_own);
DEBUGASSERT(pages != NULL && npages > 0);
DEBUGASSERT(vaddr >= CONFIG_ARCH_SHM_VBASE && vaddr < ARCH_SHM_VEND);
DEBUGASSERT(MM_ISALIGNED(vaddr));
group = tcb->group;
ptlevel = RV_MMU_PT_LEVELS;
addrenv = &tcb->addrenv_own->addrenv;
ptlevel = RV_MMU_PT_LEVELS;
/* Add the references to pages[] into the caller's address environment */
@ -88,7 +88,7 @@ int up_shmat(uintptr_t *pages, unsigned int npages, uintptr_t vaddr)
{
/* Get the address of the last level page table */
ptlast = riscv_pgvaddr(riscv_get_pgtable(&group->tg_addrenv, vaddr));
ptlast = riscv_pgvaddr(riscv_get_pgtable(addrenv, vaddr));
if (!ptlast)
{
return -ENOMEM;
@ -127,23 +127,23 @@ int up_shmat(uintptr_t *pages, unsigned int npages, uintptr_t vaddr)
int up_shmdt(uintptr_t vaddr, unsigned int npages)
{
struct tcb_s *tcb = nxsched_self();
struct task_group_s *group;
uintptr_t ptlast;
uintptr_t ptprev;
uintptr_t ptlevel;
uintptr_t paddr;
struct tcb_s *tcb = nxsched_self();
struct arch_addrenv_s *addrenv;
uintptr_t ptlast;
uintptr_t ptprev;
uintptr_t ptlevel;
uintptr_t paddr;
/* Sanity checks */
DEBUGASSERT(tcb && tcb->group);
DEBUGASSERT(tcb && tcb->addrenv_own);
DEBUGASSERT(npages > 0);
DEBUGASSERT(vaddr >= CONFIG_ARCH_SHM_VBASE && vaddr < ARCH_SHM_VEND);
DEBUGASSERT(MM_ISALIGNED(vaddr));
group = tcb->group;
ptlevel = ARCH_SPGTS;
ptprev = riscv_pgvaddr(group->tg_addrenv.spgtables[ARCH_SPGTS - 1]);
addrenv = &tcb->addrenv_own->addrenv;
ptlevel = ARCH_SPGTS;
ptprev = riscv_pgvaddr(addrenv->spgtables[ARCH_SPGTS - 1]);
if (!ptprev)
{
/* Something is very wrong */

View File

@ -163,7 +163,7 @@ size_t up_check_tcbstack(struct tcb_s *tcb)
if ((tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_KERNEL)
{
up_addrenv_select(&tcb->group->tg_addrenv, &oldenv);
up_addrenv_select(&tcb->addrenv_own->addrenv, &oldenv);
saved = true;
}
#endif

View File

@ -28,12 +28,12 @@
#include <assert.h>
#include <nuttx/irq.h>
#include <nuttx/addrenv.h>
#include <nuttx/arch.h>
#include <nuttx/board.h>
#include <arch/board/board.h>
#include "riscv_internal.h"
#include "group/group.h"
/****************************************************************************
* Pre-processor Definitions
@ -98,7 +98,7 @@ uintptr_t *riscv_doirq(int irq, uintptr_t *regs)
* thread at the head of the ready-to-run list.
*/
group_addrenv(NULL);
addrenv_switch(NULL);
}
#endif

View File

@ -94,14 +94,14 @@
uintptr_t pgalloc(uintptr_t brkaddr, unsigned int npages)
{
struct tcb_s *tcb = nxsched_self();
struct task_group_s *group;
uintptr_t ptlast;
uintptr_t paddr;
uintptr_t vaddr;
struct tcb_s *tcb = nxsched_self();
struct arch_addrenv_s *addrenv;
uintptr_t ptlast;
uintptr_t paddr;
uintptr_t vaddr;
DEBUGASSERT(tcb && tcb->group);
group = tcb->group;
DEBUGASSERT(tcb && tcb->addrenv_own);
addrenv = &tcb->addrenv_own->addrenv;
/* The current implementation only supports extending the user heap
* region as part of the implementation of user sbrk(). This function
@ -109,13 +109,11 @@ uintptr_t pgalloc(uintptr_t brkaddr, unsigned int npages)
* space and (2) extending the kernel memory regions as well.
*/
DEBUGASSERT((group->tg_flags & GROUP_FLAG_ADDRENV) != 0);
/* brkaddr = 0 means that no heap has yet been allocated */
if (!brkaddr)
{
brkaddr = group->tg_addrenv.heapvbase;
brkaddr = addrenv->heapvbase;
}
/* Start mapping from the old heap break address */
@ -124,14 +122,14 @@ uintptr_t pgalloc(uintptr_t brkaddr, unsigned int npages)
/* Sanity checks */
DEBUGASSERT(brkaddr >= group->tg_addrenv.heapvbase);
DEBUGASSERT(brkaddr >= addrenv->heapvbase);
DEBUGASSERT(MM_ISALIGNED(brkaddr));
for (; npages > 0; npages--)
{
/* Get the address of the last level page table */
ptlast = riscv_pgvaddr(riscv_get_pgtable(&group->tg_addrenv, vaddr));
ptlast = riscv_pgvaddr(riscv_get_pgtable(addrenv, vaddr));
if (!ptlast)
{
return 0;

View File

@ -26,8 +26,9 @@
#include <stdint.h>
#include <nuttx/addrenv.h>
#include "riscv_internal.h"
#include "group/group.h"
/****************************************************************************
* Public Functions
@ -52,7 +53,7 @@ void *riscv_perform_syscall(uintptr_t *regs)
* thread at the head of the ready-to-run list.
*/
group_addrenv(NULL);
addrenv_switch(NULL);
}
#endif

View File

@ -27,6 +27,7 @@
#include <stdint.h>
#include <assert.h>
#include <nuttx/addrenv.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/board.h>
@ -35,7 +36,6 @@
#include "chip/switch.h"
#include "z80_internal.h"
#include "group/group.h"
/****************************************************************************
* Public Functions
@ -82,7 +82,7 @@ FAR chipreg_t *z80_doirq(uint8_t irq, FAR chipreg_t *regs)
* ready-to-run list.
*/
group_addrenv(NULL);
addrenv_switch(NULL);
}
regs = newregs;

View File

@ -28,6 +28,7 @@
#include <sched.h>
#include <debug.h>
#include <nuttx/addrenv.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#ifdef CONFIG_DUMP_ON_EXIT
@ -143,7 +144,7 @@ void up_exit(int status)
* the ready-to-run list.
*/
group_addrenv(tcb);
addrenv_switch(tcb);
#endif
/* Then switch contexts */

View File

@ -28,13 +28,13 @@
#include <assert.h>
#include <debug.h>
#include <nuttx/addrenv.h>
#include <nuttx/arch.h>
#include <nuttx/sched.h>
#include "chip.h"
#include "chip/switch.h"
#include "sched/sched.h"
#include "group/group.h"
#include "clock/clock.h"
#include "z80_internal.h"
@ -99,7 +99,7 @@ void up_switch_context(FAR struct tcb_s *tcb, FAR struct tcb_s *rtcb)
* thread at the head of the ready-to-run list.
*/
group_addrenv(tcb);
addrenv_switch(tcb);
#endif
/* Update scheduler parameters */

View File

@ -560,7 +560,7 @@ int up_addrenv_clone(FAR const arch_addrenv_t *src,
* group.
*
* Input Parameters:
* group - The task group to which the new thread belongs.
* ptcb - The tcb of the parent task.
* tcb - The tcb of the thread needing the address environment.
*
* Returned Value:
@ -568,7 +568,7 @@ int up_addrenv_clone(FAR const arch_addrenv_t *src,
*
****************************************************************************/
int up_addrenv_attach(FAR struct task_group_s *group, FAR struct tcb_s *tcb)
int up_addrenv_attach(FAR struct tcb_s *ptcb, FAR struct tcb_s *tcb)
{
/* There is nothing that needs to be done */
@ -590,7 +590,6 @@ int up_addrenv_attach(FAR struct task_group_s *group, FAR struct tcb_s *tcb)
* may be sufficient.
*
* Input Parameters:
* group - The group to which the thread belonged.
* tcb - The TCB of the task or thread whose the address environment will
* be released.
*
@ -599,7 +598,7 @@ int up_addrenv_attach(FAR struct task_group_s *group, FAR struct tcb_s *tcb)
*
****************************************************************************/
int up_addrenv_detach(FAR struct task_group_s *group, FAR struct tcb_s *tcb)
int up_addrenv_detach(FAR struct tcb_s *tcb)
{
/* There is nothing that needs to be done */

View File

@ -239,18 +239,14 @@ int exec_module(FAR const struct binary_s *binp,
#endif
#ifdef CONFIG_ARCH_ADDRENV
/* Assign the address environment to the new task group */
/* Attach the address environment to the new task */
ret = up_addrenv_clone(&binp->addrenv, &tcb->cmn.group->tg_addrenv);
ret = addrenv_attach((FAR struct tcb_s *)tcb, &binp->addrenv);
if (ret < 0)
{
berr("ERROR: up_addrenv_clone() failed: %d\n", ret);
berr("ERROR: addrenv_attach() failed: %d\n", ret);
goto errout_with_tcbinit;
}
/* Mark that this group has an address environment */
tcb->cmn.group->tg_flags |= GROUP_FLAG_ADDRENV;
#endif
#ifdef CONFIG_BINFMT_CONSTRUCTORS

View File

@ -32,6 +32,8 @@
# include <nuttx/mm/mm.h>
#endif
#include <arch/arch.h>
#ifdef CONFIG_ARCH_ADDRENV
/****************************************************************************
@ -218,6 +220,11 @@
(CONFIG_ARCH_PGPOOL_VBASE + CONFIG_ARCH_PGPOOL_SIZE)
#endif
/****************************************************************************
* Public Type Definitions
****************************************************************************/
struct tcb_s; /* Forward reference to TCB */
/****************************************************************************
* Public Types
@ -225,6 +232,13 @@
#ifndef __ASSEMBLY__
struct addrenv_s
{
struct arch_addrenv_s addrenv; /* The address environment page directory */
};
typedef struct addrenv_s addrenv_t;
/* Reserved .bss/.data region. In the kernel build (CONFIG_BUILD_KERNEL),
* the region at the beginning of the .bss/.data region is reserved for use
* by the OS. This reserved region contains support for:
@ -269,6 +283,83 @@ struct addrenv_reserve_s
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: addrenv_allocate
*
* Description:
* Allocate an address environment for a new process.
*
* Input Parameters:
* tcb - The tcb of the newly created task.
* ttype - The type of the task.
*
* Returned Value:
* This is a NuttX internal function so it follows the convention that
* 0 (OK) is returned on success and a negated errno is returned on
* failure.
*
****************************************************************************/
int addrenv_allocate(FAR struct tcb_s *tcb, uint8_t ttype);
/****************************************************************************
* Name: addrenv_free
*
* Description:
* Free an address environment for a process.
*
* Input Parameters:
* tcb - The tcb of the task.
*
* Returned Value:
* This is a NuttX internal function so it follows the convention that
* 0 (OK) is returned on success and a negated errno is returned on
* failure.
*
****************************************************************************/
int addrenv_free(FAR struct tcb_s *tcb);
/****************************************************************************
* Name: addrenv_switch
*
* Description:
* Switch to an address environment.
*
* Input Parameters:
* tcb - The tcb of the task to switch to, or NULL to use the task at the
* head of the ready-to-run list.
*
* Returned Value:
* This is a NuttX internal function so it follows the convention that
* 0 (OK) is returned on success and a negated errno is returned on
* failure.
*
****************************************************************************/
int addrenv_switch(FAR struct tcb_s *tcb);
/****************************************************************************
* Name: addrenv_attach
*
* Description:
* Attach address environment to a newly process. Called by exec() right
* before injecting the new process into the system.
*
* Input Parameters:
* tcb - The tcb of the newly loaded task.
* addrenv - The address environment that is attached.
*
* Returned Value:
* This is a NuttX internal function so it follows the convention that
* 0 (OK) is returned on success and a negated errno is returned on
* failure.
*
****************************************************************************/
int addrenv_attach(FAR struct tcb_s *tcb,
FAR const struct arch_addrenv_s *addrenv);
/****************************************************************************
* Address Environment Interfaces
*

View File

@ -1094,13 +1094,9 @@ int up_addrenv_clone(FAR const arch_addrenv_t *src,
* is created that needs to share the address environment of its task
* group.
*
* NOTE: In some platforms, nothing will need to be done in this case.
* Simply being a member of the group that has the address environment
* may be sufficient.
*
* Input Parameters:
* group - The task group to which the new thread belongs.
* tcb - The TCB of the thread needing the address environment.
* ptcb - The tcb of the parent task.
* tcb - The tcb of the thread needing the address environment.
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
@ -1108,7 +1104,7 @@ int up_addrenv_clone(FAR const arch_addrenv_t *src,
****************************************************************************/
#ifdef CONFIG_ARCH_ADDRENV
int up_addrenv_attach(FAR struct task_group_s *group, FAR struct tcb_s *tcb);
int up_addrenv_attach(FAR struct tcb_s *ptcb, FAR struct tcb_s *tcb);
#endif
/****************************************************************************
@ -1121,12 +1117,7 @@ int up_addrenv_attach(FAR struct task_group_s *group, FAR struct tcb_s *tcb);
* task group is itself destroyed. Any resources unique to this thread
* may be destroyed now.
*
* NOTE: In some platforms, nothing will need to be done in this case.
* Simply being a member of the group that has the address environment
* may be sufficient.
*
* Input Parameters:
* group - The group to which the thread belonged.
* tcb - The TCB of the task or thread whose the address environment will
* be released.
*
@ -1136,7 +1127,7 @@ int up_addrenv_attach(FAR struct task_group_s *group, FAR struct tcb_s *tcb);
****************************************************************************/
#ifdef CONFIG_ARCH_ADDRENV
int up_addrenv_detach(FAR struct task_group_s *group, FAR struct tcb_s *tcb);
int up_addrenv_detach(FAR struct tcb_s *tcb);
#endif
/****************************************************************************

View File

@ -34,6 +34,7 @@
#include <pthread.h>
#include <time.h>
#include <nuttx/addrenv.h>
#include <nuttx/clock.h>
#include <nuttx/irq.h>
#include <nuttx/mutex.h>
@ -107,10 +108,9 @@
/* Values for struct task_group tg_flags */
#define GROUP_FLAG_NOCLDWAIT (1 << 0) /* Bit 0: Do not retain child exit status */
#define GROUP_FLAG_ADDRENV (1 << 1) /* Bit 1: Group has an address environment */
#define GROUP_FLAG_PRIVILEGED (1 << 2) /* Bit 2: Group is privileged */
#define GROUP_FLAG_DELETED (1 << 3) /* Bit 3: Group has been deleted but not yet freed */
/* Bits 4-7: Available */
#define GROUP_FLAG_PRIVILEGED (1 << 1) /* Bit 1: Group is privileged */
#define GROUP_FLAG_DELETED (1 << 2) /* Bit 2: Group has been deleted but not yet freed */
/* Bits 3-7: Available */
/* Values for struct child_status_s ch_flags */
@ -418,7 +418,7 @@ struct binary_s; /* Forward reference
struct task_group_s
{
#if defined(HAVE_GROUP_MEMBERS) || defined(CONFIG_ARCH_ADDRENV)
#if defined(HAVE_GROUP_MEMBERS)
struct task_group_s *flink; /* Supports a singly linked list */
#endif
pid_t tg_pid; /* The ID of the task within the group */
@ -512,12 +512,6 @@ struct task_group_s
struct filelist tg_filelist; /* Maps file descriptor to file */
#ifdef CONFIG_ARCH_ADDRENV
/* Address Environment ****************************************************/
arch_addrenv_t tg_addrenv; /* Task group address environment */
#endif
/* Virtual memory mapping info ********************************************/
struct mm_map_s tg_mm_map; /* Task mmappings */
@ -542,6 +536,12 @@ struct tcb_s
FAR struct task_group_s *group; /* Pointer to shared task group data */
/* Address Environment ****************************************************/
#ifdef CONFIG_ARCH_ADDRENV
FAR struct addrenv_s *addrenv_own; /* Task (group) own memory mappings */
#endif
/* Task Management Fields *************************************************/
pid_t pid; /* This is the ID of the thread */

View File

@ -20,6 +20,7 @@
include $(TOPDIR)/Make.defs
include addrenv/Make.defs
include clock/Make.defs
include environ/Make.defs
include group/Make.defs

28
sched/addrenv/Make.defs Normal file
View File

@ -0,0 +1,28 @@
############################################################################
# sched/addrenv/Make.defs
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################
ifeq ($(CONFIG_ARCH_ADDRENV),y)
CSRCS += addrenv.c
endif
# Include addrenv build support
DEPPATH += --dep-path addrenv
VPATH += :addrenv

View File

@ -1,5 +1,5 @@
/****************************************************************************
* sched/group/group_addrenv.c
* sched/addrenv/addrenv.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@ -27,33 +27,37 @@
#include <assert.h>
#include <debug.h>
#include <nuttx/addrenv.h>
#include <nuttx/irq.h>
#include <nuttx/sched.h>
#include "sched/sched.h"
#include "group/group.h"
#ifdef CONFIG_ARCH_ADDRENV
/****************************************************************************
* Public Data
* Pre-processor Definitions
****************************************************************************/
/* This variable holds the current task group. This pointer is NULL
* if the current task is a kernel thread that has no address environment
* (other than the kernel context).
/****************************************************************************
* Private Data
****************************************************************************/
/* This variable holds the current address environment. These contents are
* _never_ NULL, besides when the system is started and there are only the
* initial kernel mappings available.
*
* This must only be accessed with interrupts disabled.
*
* REVISIT: Try to get rid of this, global bookkeeping for this is dangerous.
*/
FAR struct task_group_s *g_group_current[CONFIG_SMP_NCPUS];
static FAR struct addrenv_s *g_addrenv[CONFIG_SMP_NCPUS];
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: group_addrenv
* Name: addrenv_switch
*
* Description:
* Instantiate the group address environment for the current thread at the
@ -80,10 +84,10 @@ FAR struct task_group_s *g_group_current[CONFIG_SMP_NCPUS];
*
****************************************************************************/
int group_addrenv(FAR struct tcb_s *tcb)
int addrenv_switch(FAR struct tcb_s *tcb)
{
FAR struct task_group_s *group;
FAR struct task_group_s *oldgroup;
FAR struct addrenv_s *curr;
FAR struct addrenv_s *next;
irqstate_t flags;
int cpu;
int ret;
@ -97,12 +101,12 @@ int group_addrenv(FAR struct tcb_s *tcb)
tcb = this_task();
}
DEBUGASSERT(tcb && tcb->group);
group = tcb->group;
DEBUGASSERT(tcb);
next = tcb->mm_curr;
/* Does the group have an address environment? */
if ((group->tg_flags & GROUP_FLAG_ADDRENV) == 0)
if (!next)
{
/* No... just return perhaps leaving a different address environment
* intact.
@ -111,24 +115,24 @@ int group_addrenv(FAR struct tcb_s *tcb)
return OK;
}
/* Are we going to change address environments? */
flags = enter_critical_section();
cpu = this_cpu();
oldgroup = g_group_current[cpu];
if (group != oldgroup)
curr = g_addrenv[cpu];
/* Are we going to change address environments? */
if (curr != next)
{
/* Yes.. Is there a current address environment in place? */
if (oldgroup)
if (curr)
{
/* We need to flush the D-Cache and Invalidate the I-Cache for
* the group whose environment is disappearing.
*/
DEBUGASSERT((oldgroup->tg_flags & GROUP_FLAG_ADDRENV) != 0);
up_addrenv_coherent(&oldgroup->tg_addrenv);
up_addrenv_coherent(&curr->addrenv);
}
/* Instantiate the new address environment (removing the old
@ -137,19 +141,115 @@ int group_addrenv(FAR struct tcb_s *tcb)
* instantiated.
*/
ret = up_addrenv_select(&group->tg_addrenv, NULL);
ret = up_addrenv_select(&next->addrenv, NULL);
if (ret < 0)
{
berr("ERROR: up_addrenv_select failed: %d\n", ret);
}
/* Save the new, current group */
/* Save the new, current address environment group */
g_group_current[cpu] = group;
g_addrenv[cpu] = next;
}
leave_critical_section(flags);
return OK;
}
#endif /* CONFIG_ARCH_ADDRENV */
/****************************************************************************
* Name: addrenv_allocate
*
* Description:
* Allocate an address environment for a new process.
*
* Input Parameters:
* tcb - The tcb of the newly created task.
* ttype - The type of the task.
*
* Returned Value:
* This is a NuttX internal function so it follows the convention that
* 0 (OK) is returned on success and a negated errno is returned on
* failure.
*
****************************************************************************/
int addrenv_allocate(FAR struct tcb_s *tcb, uint8_t ttype)
{
int ret = OK;
if ((ttype & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_KERNEL)
{
tcb->addrenv_own = NULL;
}
else
{
tcb->addrenv_own = (FAR struct addrenv_s *)
kmm_zalloc(sizeof(struct addrenv_s));
if (tcb->addrenv_own == NULL)
{
ret = -ENOMEM;
}
}
return ret;
}
/****************************************************************************
* Name: addrenv_free
*
* Description:
* Free an address environment for a process.
*
* Input Parameters:
* tcb - The tcb of the task.
*
* Returned Value:
* This is a NuttX internal function so it follows the convention that
* 0 (OK) is returned on success and a negated errno is returned on
* failure.
*
****************************************************************************/
int addrenv_free(FAR struct tcb_s *tcb)
{
if (tcb->addrenv_own != NULL)
{
kmm_free(tcb->addrenv_own);
}
return OK;
}
/****************************************************************************
* Name: addrenv_attach
*
* Description:
* Attach address environment to a newly created group. Called by exec()
* right before injecting the new process into the system.
*
* Input Parameters:
* tcb - The tcb of the newly loaded task.
* addrenv - The address environment that is attached.
*
* Returned Value:
* This is a NuttX internal function so it follows the convention that
* 0 (OK) is returned on success and a negated errno is returned on
* failure.
*
****************************************************************************/
int addrenv_attach(FAR struct tcb_s *tcb,
FAR const struct arch_addrenv_s *addrenv)
{
int ret;
/* Clone the address environment for us */
ret = up_addrenv_clone(addrenv, &tcb->addrenv_own->addrenv);
if (ret < 0)
{
berr("ERROR: up_addrenv_clone failed: %d\n", ret);
}
return OK;
}

View File

@ -36,10 +36,6 @@ ifeq ($(CONFIG_SCHED_USER_IDENTITY),y)
CSRCS += group_setuid.c group_setgid.c group_getuid.c group_getgid.c
endif
ifeq ($(CONFIG_ARCH_ADDRENV),y)
CSRCS += group_addrenv.c
endif
ifeq ($(CONFIG_SIG_SIGSTOP_ACTION),y)
CSRCS += group_suspendchildren.c group_continue.c
endif

View File

@ -44,23 +44,12 @@ typedef int (*foreachchild_t)(pid_t pid, FAR void *arg);
* Public Data
****************************************************************************/
#if defined(HAVE_GROUP_MEMBERS) || defined(CONFIG_ARCH_ADDRENV)
#if defined(HAVE_GROUP_MEMBERS)
/* This is the head of a list of all group members */
extern FAR struct task_group_s *g_grouphead;
#endif
#ifdef CONFIG_ARCH_ADDRENV
/* This variable holds the current task group. This pointer is NULL
* if the current task is a kernel thread that has no address environment
* (other than the kernel context).
*
* This must only be accessed with interrupts disabled.
*/
extern FAR struct task_group_s *g_group_current[CONFIG_SMP_NCPUS];
#endif
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
@ -86,7 +75,7 @@ void group_add_waiter(FAR struct task_group_s *group);
void group_del_waiter(FAR struct task_group_s *group);
#endif
#if defined(HAVE_GROUP_MEMBERS) || defined(CONFIG_ARCH_ADDRENV)
#if defined(HAVE_GROUP_MEMBERS)
FAR struct task_group_s *group_findbypid(pid_t pid);
#endif
@ -100,12 +89,6 @@ int group_continue(FAR struct tcb_s *tcb);
#endif
#endif
#ifdef CONFIG_ARCH_ADDRENV
/* Group address environment management */
int group_addrenv(FAR struct tcb_s *tcb);
#endif
/* Convenience functions */
FAR struct task_group_s *task_getgroup(pid_t pid);

View File

@ -51,7 +51,7 @@
* Public Data
****************************************************************************/
#if defined(HAVE_GROUP_MEMBERS) || defined(CONFIG_ARCH_ADDRENV)
#if defined(HAVE_GROUP_MEMBERS)
/* This is the head of a list of all group members */
FAR struct task_group_s *g_grouphead;
@ -231,7 +231,7 @@ errout_with_group:
void group_initialize(FAR struct task_tcb_s *tcb)
{
FAR struct task_group_s *group;
#if defined(HAVE_GROUP_MEMBERS) || defined(CONFIG_ARCH_ADDRENV)
#if defined(HAVE_GROUP_MEMBERS)
irqstate_t flags;
#endif
@ -261,7 +261,7 @@ void group_initialize(FAR struct task_tcb_s *tcb)
group->tg_nmembers = 1;
#if defined(HAVE_GROUP_MEMBERS) || defined(CONFIG_ARCH_ADDRENV)
#if defined(HAVE_GROUP_MEMBERS)
/* Add the initialized entry to the list of groups */
flags = enter_critical_section();

View File

@ -63,7 +63,7 @@
*
****************************************************************************/
#if defined(HAVE_GROUP_MEMBERS) || defined(CONFIG_ARCH_ADDRENV)
#if defined(HAVE_GROUP_MEMBERS)
FAR struct task_group_s *group_findbypid(pid_t pid)
{
FAR struct task_group_s *group;

View File

@ -67,7 +67,7 @@
*
****************************************************************************/
#if defined(HAVE_GROUP_MEMBERS) || defined(CONFIG_ARCH_ADDRENV)
#if defined(HAVE_GROUP_MEMBERS)
static void group_remove(FAR struct task_group_s *group)
{
FAR struct task_group_s *curr;
@ -128,10 +128,6 @@ static void group_remove(FAR struct task_group_s *group)
static inline void group_release(FAR struct task_group_s *group)
{
#ifdef CONFIG_ARCH_ADDRENV
int i;
#endif
#if CONFIG_TLS_TASK_NELEM > 0
task_tls_destruct();
#endif
@ -172,7 +168,7 @@ static inline void group_release(FAR struct task_group_s *group)
mm_map_destroy(&group->tg_mm_map);
#if defined(HAVE_GROUP_MEMBERS) || defined(CONFIG_ARCH_ADDRENV)
#if defined(HAVE_GROUP_MEMBERS)
/* Remove the group from the list of groups */
group_remove(group);
@ -201,22 +197,6 @@ static inline void group_release(FAR struct task_group_s *group)
}
#endif
#ifdef CONFIG_ARCH_ADDRENV
/* Destroy the group address environment */
up_addrenv_destroy(&group->tg_addrenv);
/* Mark no address environment */
for (i = 0; i < CONFIG_SMP_NCPUS; i++)
{
if (group == g_group_current[i])
{
g_group_current[i] = NULL;
}
}
#endif
/* Mark the group as deleted now */
group->tg_flags |= GROUP_FLAG_DELETED;

View File

@ -242,7 +242,7 @@ static void get_argv_str(FAR struct tcb_s *tcb, FAR char *args, size_t size)
#ifdef CONFIG_ARCH_ADDRENV
if ((tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_KERNEL)
{
if ((tcb->group->tg_flags & GROUP_FLAG_ADDRENV) == 0)
if (tcb->addrenv_own == NULL)
{
/* Process should have address environment, but doesn't */
@ -250,7 +250,7 @@ static void get_argv_str(FAR struct tcb_s *tcb, FAR char *args, size_t size)
return;
}
up_addrenv_select(&tcb->group->tg_addrenv, &oldenv);
up_addrenv_select(&tcb->addrenv_own->addrenv, &oldenv);
saved = true;
}
#endif

View File

@ -220,7 +220,7 @@ int nx_pthread_create(pthread_trampoline_t trampoline, FAR pthread_t *thread,
#ifdef CONFIG_ARCH_ADDRENV
/* Share the address environment of the parent task group. */
ret = up_addrenv_attach(ptcb->cmn.group, this_task());
ret = up_addrenv_attach(this_task(), (FAR struct tcb_s *)ptcb);
if (ret < 0)
{
errcode = -ret;

View File

@ -154,7 +154,11 @@ int nxsched_release_tcb(FAR struct tcb_s *tcb, uint8_t ttype)
#ifdef CONFIG_ARCH_ADDRENV
/* Release this thread's reference to the address environment */
ret = up_addrenv_detach(tcb->group, tcb);
ret = up_addrenv_detach(tcb);
if (ttype == TCB_FLAG_TTYPE_TASK)
{
addrenv_free(tcb);
}
#endif
/* Leave the group (if we did not already leave in task_exithook.c) */

View File

@ -96,12 +96,22 @@ int nxtask_init(FAR struct task_tcb_s *tcb, const char *name, int priority,
DEBUGASSERT(tcb && ttype != TCB_FLAG_TTYPE_PTHREAD);
#endif
#ifdef CONFIG_ARCH_ADDRENV
/* Allocate address environment for the task */
ret = addrenv_allocate(&tcb->cmn, tcb->cmn.flags);
if (ret < 0)
{
return ret;
}
#endif
/* Create a new task group */
ret = group_allocate(tcb, tcb->cmn.flags);
if (ret < 0)
{
return ret;
goto errout_with_addrenv;
}
/* Duplicate the parent tasks environment */
@ -190,6 +200,11 @@ errout_with_group:
}
group_leave(&tcb->cmn);
errout_with_addrenv:
#ifdef CONFIG_ARCH_ADDRENV
addrenv_free(&tcb->cmn);
#endif
return ret;
}