mirror of
https://github.com/apache/nuttx.git
synced 2026-09-30 11:03:53 +00:00
The base firmware and an FDPIC module disagree about what a function pointer is. Firmware is not built FDPIC, so to it a pointer is a code address and it branches there. A module passes the address of a two word descriptor instead, because its code and data are placed independently and a bare code address would leave the callee unable to find its own data. A firmware routine that takes a callback therefore branches into the module's data segment and faults. So the ten entry points that can be handed a callback by a module resolve the descriptor before storing or branching to it: qsort, bsearch, pthread_create, signal, sigaction, task_create and task_create_with_stack, task_spawn, pthread_once, scandir, and mq_notify and timer_create with SIGEV_THREAD. Which one resolves matters as much as that one does. Resolving twice would take an already resolved code address for a descriptor and read two words from the instruction stream, so each pointer is resolved exactly once, at the outermost point that sees it. signal() passes its argument through untouched because sigaction() and then nxsig_action() will resolve it, which covers a module calling sigaction() directly as well. qsort() is split so that the public entry resolves and the recursive implementation does not. scandir() resolves its filter but not its comparison function, which it hands to qsort(). Whether a caller is a module at all is asked of the PIC base register, which up_initial_state() sets only for a task that has a D-Space. A plain kernel task therefore reads zero and is left alone. SIGEV_THREAD is the case the register cannot answer, because the callback runs later on a work queue worker that carries no module's base at all. The base is captured instead when the notification is registered, in the module's own context, and installed around the call. All of it is behind CONFIG_FDPIC, which defaults off. Built for mps3-an547:picostest both ways; with it off the entry points compile to what they were. Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
300 lines
11 KiB
C
300 lines
11 KiB
C
/****************************************************************************
|
|
* sched/task/task_create.c
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* 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.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sched.h>
|
|
#include <errno.h>
|
|
#include <nuttx/debug.h>
|
|
|
|
#include <nuttx/arch.h>
|
|
#include <nuttx/kmalloc.h>
|
|
#include <nuttx/sched.h>
|
|
#include <nuttx/kthread.h>
|
|
#include <nuttx/fs/fs.h>
|
|
|
|
#ifdef CONFIG_FDPIC
|
|
# include <nuttx/fdpic.h>
|
|
#endif
|
|
|
|
#include "sched/sched.h"
|
|
#include "group/group.h"
|
|
#include "task/task.h"
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: nxthread_create
|
|
*
|
|
* Description:
|
|
* This function creates and activates a new thread of the specified type
|
|
* with a specified priority and returns its system-assigned ID. It is the
|
|
* internal, common implementation of task_create() and kthread_create().
|
|
* See comments with task_create() for further information.
|
|
*
|
|
* Input Parameters:
|
|
* name - Name of the new task
|
|
* ttype - Type of the new task
|
|
* priority - Priority of the new task
|
|
* stack_addr - Address of the stack needed
|
|
* stack_size - Size (in bytes) of the stack needed
|
|
* entry - Entry point of a new task
|
|
* arg - A pointer to an array of input parameters. The array
|
|
* should be terminated with a NULL argv[] value. If no
|
|
* parameters are required, argv may be NULL.
|
|
* envp - A pointer to an array of environment strings. Terminated
|
|
* with a NULL entry.
|
|
*
|
|
* Returned Value:
|
|
* Returns the positive, non-zero process ID of the new task or a negated
|
|
* errno value to indicate the nature of any failure. If memory is
|
|
* insufficient or the task cannot be created -ENOMEM will be returned.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int nxthread_create(FAR const char *name, uint8_t ttype, int priority,
|
|
FAR void *stack_addr, int stack_size, main_t entry,
|
|
FAR char * const argv[], FAR char * const envp[])
|
|
{
|
|
FAR struct tcb_s *tcb;
|
|
pid_t pid;
|
|
int ret;
|
|
|
|
/* Allocate a TCB for the new task. */
|
|
|
|
tcb = kmm_zalloc(sizeof(struct tcb_s));
|
|
if (!tcb)
|
|
{
|
|
serr("ERROR: Failed to allocate TCB\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* Setup the task type */
|
|
|
|
tcb->flags = ttype | TCB_FLAG_FREE_TCB;
|
|
|
|
/* Initialize the task */
|
|
|
|
ret = nxtask_init(tcb, name, priority,
|
|
stack_addr, stack_size, entry, argv, envp, NULL);
|
|
if (ret < OK)
|
|
{
|
|
kmm_free(tcb);
|
|
return ret;
|
|
}
|
|
|
|
/* Get the assigned pid before we start the task */
|
|
|
|
pid = tcb->pid;
|
|
|
|
/* Activate the task */
|
|
|
|
nxtask_activate(tcb);
|
|
|
|
return pid;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: nxtask_create
|
|
*
|
|
* Description:
|
|
* This function creates and activates a new task with a specified
|
|
* priority and returns its system-assigned ID.
|
|
*
|
|
* The entry address entry is the address of the "main" function of the
|
|
* task. This function will be called once the C environment has been
|
|
* set up. The specified function will be called with four arguments.
|
|
* Should the specified routine return, a call to exit() will
|
|
* automatically be made.
|
|
*
|
|
* Note that four (and only four) arguments must be passed for the spawned
|
|
* functions.
|
|
*
|
|
* nxtask_create() is identical to the function task_create(), differing
|
|
* only in its return value: This function does not modify the errno
|
|
* variable. This is a non-standard, internal OS function and is not
|
|
* intended for use by application logic. Applications should use
|
|
* task_create().
|
|
*
|
|
* Input Parameters:
|
|
* name - Name of the new task
|
|
* priority - Priority of the new task
|
|
* stack_addr - Address of the stack needed
|
|
* stack_size - Size (in bytes) of the stack needed
|
|
* entry - Entry point of a new task
|
|
* arg - A pointer to an array of input parameters. The array
|
|
* should be terminated with a NULL argv[] value. If no
|
|
* parameters are required, argv may be NULL.
|
|
* envp - A pointer to an array of environment strings. Terminated
|
|
* with a NULL entry.
|
|
*
|
|
* Returned Value:
|
|
* Returns the positive, non-zero process ID of the new task or a negated
|
|
* errno value to indicate the nature of any failure. If memory is
|
|
* insufficient or the task cannot be created -ENOMEM will be returned.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int nxtask_create(FAR const char *name, int priority,
|
|
FAR void *stack_addr, int stack_size, main_t entry,
|
|
FAR char * const argv[], FAR char * const envp[])
|
|
{
|
|
return nxthread_create(name, TCB_FLAG_TTYPE_TASK, priority, stack_addr,
|
|
stack_size, entry, argv, envp ? envp : environ);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: task_create
|
|
*
|
|
* Description:
|
|
* This function creates and activates a new task with a specified
|
|
* priority and returns its system-assigned ID.
|
|
*
|
|
* The entry address entry is the address of the "main" function of the
|
|
* task. This function will be called once the C environment has been
|
|
* set up. The specified function will be called with four arguments.
|
|
* Should the specified routine return, a call to exit() will
|
|
* automatically be made.
|
|
*
|
|
* Note that four (and only four) arguments must be passed for the spawned
|
|
* functions.
|
|
*
|
|
* Input Parameters:
|
|
* name - Name of the new task
|
|
* priority - Priority of the new task
|
|
* stack_size - size (in bytes) of the stack needed
|
|
* entry - Entry point of a new task
|
|
* arg - A pointer to an array of input parameters. The array
|
|
* should be terminated with a NULL argv[] value. If no
|
|
* parameters are required, argv may be NULL.
|
|
*
|
|
* Returned Value:
|
|
* Returns the non-zero process ID of the new task or ERROR if memory is
|
|
* insufficient or the task cannot be created. The errno will be set in
|
|
* the failure case to indicate the nature of the error.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifndef CONFIG_BUILD_KERNEL
|
|
int task_create_with_stack(FAR const char *name, int priority,
|
|
FAR void *stack_addr, int stack_size,
|
|
main_t entry, FAR char * const argv[])
|
|
{
|
|
int ret;
|
|
|
|
#ifdef CONFIG_FDPIC
|
|
/* Resolve here, once: this covers task_create() too, which is a plain
|
|
* forwarder. The new task inherits the creator's D-Space.
|
|
*/
|
|
|
|
entry = (main_t)fdpic_callback((FAR void *)entry);
|
|
#endif
|
|
|
|
ret = nxtask_create(name, priority, stack_addr,
|
|
stack_size, entry, argv, NULL);
|
|
if (ret < 0)
|
|
{
|
|
set_errno(-ret);
|
|
ret = ERROR;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int task_create(FAR const char *name, int priority,
|
|
int stack_size, main_t entry, FAR char * const argv[])
|
|
{
|
|
return task_create_with_stack(name, priority, NULL,
|
|
stack_size, entry, argv);
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: kthread_create_with_stack
|
|
*
|
|
* Description:
|
|
* This function creates and activates a kernel thread task with
|
|
* kernel-mode privileges. It is identical to kthread_create() except
|
|
* that it get the stack memory from caller.
|
|
*
|
|
* Input Parameters:
|
|
* name - Name of the new task
|
|
* priority - Priority of the new task
|
|
* stack_addr - Stack buffer of the new task
|
|
* stack_size - Stack size of the new task
|
|
* entry - Entry point of a new task
|
|
* arg - A pointer to an array of input parameters. The array
|
|
* should be terminated with a NULL argv[] value. If no
|
|
* parameters are required, argv may be NULL.
|
|
*
|
|
* Returned Value:
|
|
* Returns the positive, non-zero process ID of the new task or a negated
|
|
* errno value to indicate the nature of any failure. If memory is
|
|
* insufficient or the task cannot be created -ENOMEM will be returned.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int kthread_create_with_stack(FAR const char *name, int priority,
|
|
FAR void *stack_addr, int stack_size,
|
|
main_t entry, FAR char * const argv[])
|
|
{
|
|
return nxthread_create(name, TCB_FLAG_TTYPE_KERNEL, priority,
|
|
stack_addr, stack_size, entry, argv, NULL);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: kthread_create
|
|
*
|
|
* Description:
|
|
* This function creates and activates a kernel thread task with kernel-
|
|
* mode privileges. It is identical to task_create() except that it
|
|
* configures the newly started thread to run in kernel model.
|
|
*
|
|
* Input Parameters:
|
|
* name - Name of the new task
|
|
* priority - Priority of the new task
|
|
* stack_size - size (in bytes) of the stack needed
|
|
* entry - Entry point of a new task
|
|
* arg - A pointer to an array of input parameters. The array
|
|
* should be terminated with a NULL argv[] value. If no
|
|
* parameters are required, argv may be NULL.
|
|
*
|
|
* Returned Value:
|
|
* Returns the positive, non-zero process ID of the new task or a negated
|
|
* errno value to indicate the nature of any failure. If memory is
|
|
* insufficient or the task cannot be created -ENOMEM will be returned.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int kthread_create(FAR const char *name, int priority,
|
|
int stack_size, main_t entry, FAR char * const argv[])
|
|
{
|
|
return kthread_create_with_stack(name, priority,
|
|
NULL, stack_size, entry, argv);
|
|
}
|