userspace: add K_THREAD_ACCCESS_GRANT()

It's possible to declare static threads that start up as K_USER,
but these threads can't do much since they start with permissions on
no kernel objects other than their own thread object.

Rather than do some run-time synchronization to have some other thread
grant the necessary permissions, we introduce macros
to conveniently assign object permissions to these threads when they
are brought up at boot by the kernel. The tables generated here
are constant and live in ROM when possible.

Example usage:

K_THREAD_DEFINE(my_thread, STACK_SIZE, my_thread_entry,
                NULL, NULL, NULL, 0, K_USER, K_NO_WAIT);

K_THREAD_ACCESS_GRANT(my_thread, &my_sem, &my_mutex, &my_pipe);

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
Andrew Boie 2017-10-17 11:20:22 -07:00 committed by Andrew Boie
commit 877f82e847
4 changed files with 63 additions and 2 deletions

View file

@ -181,6 +181,32 @@ struct _k_object {
u32_t data;
} __packed;
struct _k_object_assignment {
struct k_thread *thread;
void * const *objects;
};
/**
* @brief Grant a static thread access to a list of kernel objects
*
* For threads declared with K_THREAD_DEFINE(), grant the thread access to
* a set of kernel objects. These objects do not need to be in an initialized
* state. The permissions will be granted when the threads are initialized
* in the early boot sequence.
*
* All arguments beyond the first must be pointers to kernel objects.
*
* @param name_ Name of the thread, as passed to K_THREAD_DEFINE()
*/
#define K_THREAD_ACCESS_GRANT(name_, ...) \
static void * const _CONCAT(_object_list_, name_)[] = \
{ __VA_ARGS__, NULL }; \
static __used __in_section_unique(object_access) \
const struct _k_object_assignment \
_CONCAT(_object_access_, name_) = \
{ (&_k_thread_obj_ ## name_), \
(_CONCAT(_object_list_, name_)) }
#define K_OBJ_FLAG_INITIALIZED BIT(0)
#define K_OBJ_FLAG_PUBLIC BIT(1)
@ -195,6 +221,9 @@ struct _k_object {
*/
void _k_object_init(void *obj);
#else
#define K_THREAD_ACCESS_GRANT(thread, ...)
static inline void _k_object_init(void *obj)
{
ARG_UNUSED(obj);

View file

@ -24,7 +24,17 @@
__init_array_end = .;
} GROUP_LINK_IN(ROMABLE_REGION)
#endif
#ifdef CONFIG_USERSPACE
/* Build-time assignment of permissions to kernel objects to
* threads declared with K_THREAD_DEFINE()
*/
SECTION_PROLOGUE(object_access, (OPTIONAL),)
{
__object_access_start = .;
KEEP(*(".object_access.*"))
__object_access_end = .;
}
#endif
SECTION_PROLOGUE (devconfig, (OPTIONAL),)
{
__devconfig_start = .;

View file

@ -590,6 +590,25 @@ void _k_thread_single_abort(struct k_thread *thread)
}
#ifdef CONFIG_MULTITHREADING
#ifdef CONFIG_USERSPACE
extern char __object_access_start[];
extern char __object_access_end[];
static void grant_static_access(void)
{
struct _k_object_assignment *pos;
for (pos = (struct _k_object_assignment *)__object_access_start;
pos < (struct _k_object_assignment *)__object_access_end;
pos++) {
for (int i = 0; pos->objects[i] != NULL; i++) {
k_object_access_grant(pos->objects[i],
pos->thread);
}
}
}
#endif /* CONFIG_USERSPACE */
void _init_static_threads(void)
{
unsigned int key;
@ -609,6 +628,9 @@ void _init_static_threads(void)
thread_data->init_thread->init_data = thread_data;
}
#ifdef CONFIG_USERSPACE
grant_static_access();
#endif
_sched_lock();
/*

View file

@ -489,7 +489,7 @@ class SizeCalculator:
"_k_queue_area", "_net_buf_pool_area", "app_datas",
"kobject_data", "mmu_tables"]
# These get copied into RAM only on non-XIP
ro_sections = ["text", "ctors", "init_array", "reset",
ro_sections = ["text", "ctors", "init_array", "reset", "object_access",
"rodata", "devconfig", "net_l2", "vector"]
def __init__(self, filename, extra_sections):