text: /*
   * Copyright (c) 2017 Intel Corporation
   *
   * SPDX-License-Identifier: Apache-2.0
   */
  
  
  #include <kernel.h>
  #include <string.h>
  #include <misc/printk.h>
  #include <kernel_structs.h>
  #include <sys_io.h>
  #include <ksched.h>
  #include <syscall.h>
  #include <syscall_handler.h>
  
  #define MAX_THREAD_BITS		(CONFIG_MAX_THREAD_BYTES * 8)
  
  const char *otype_to_str(enum k_objects otype)
  {
  	/* -fdata-sections doesn't work right except in very very recent
  	 * GCC and these literal strings would appear in the binary even if
  	 * otype_to_str was omitted by the linker
  	 */
  #ifdef CONFIG_PRINTK
  	switch (otype) {
  	/* Core kernel objects */
  	case K_OBJ_ALERT:
  		return "k_alert";
  	case K_OBJ_MSGQ:
  		return "k_msgq";
  	case K_OBJ_MUTEX:
  		return "k_mutex";
  	case K_OBJ_PIPE:
  		return "k_pipe";
  	case K_OBJ_SEM:
  		return "k_sem";
  	case K_OBJ_STACK:
  		return "k_stack";
  	case K_OBJ_THREAD:
  		return "k_thread";
  	case K_OBJ_TIMER:
  		return "k_timer";
  	case K_OBJ__THREAD_STACK_ELEMENT:
  		return "k_thread_stack_t";
  
  	/* Driver subsystems */
  	case K_OBJ_DRIVER_ADC:
  		return "adc driver";
  	case K_OBJ_DRIVER_AIO_CMP:
  		return "aio comparator driver";
  	case K_OBJ_DRIVER_COUNTER:
  		return "counter driver";
  	case K_OBJ_DRIVER_CRYPTO:
  		return "crypto driver";
  	case K_OBJ_DRIVER_DMA:
  		return "dma driver";
  	case K_OBJ_DRIVER_FLASH:
  		return "flash driver";
  	case K_OBJ_DRIVER_GPIO:
  		return "gpio driver";
  	case K_OBJ_DRIVER_I2C:
  		return "i2c driver";
  	case K_OBJ_DRIVER_I2S:
  		return "i2s driver";
  	case K_OBJ_DRIVER_IPM:
  		return "ipm driver";
  	case K_OBJ_DRIVER_PINMUX:
  		return "pinmux driver";
  	case K_OBJ_DRIVER_PWM:
  		return "pwm driver";
  	case K_OBJ_DRIVER_ENTROPY:
  		return "entropy driver";
  	case K_OBJ_DRIVER_RTC:
  		return "realtime clock driver";
  	case K_OBJ_DRIVER_SENSOR:
  		return "sensor driver";
  	case K_OBJ_DRIVER_SPI:
  		return "spi driver";
  	case K_OBJ_DRIVER_UART:
  		return "uart driver";
  	default:
  		return "?";
  	}
  #else
  	ARG_UNUSED(otype);
  	return NULL;
  #endif
  }
  
  struct perm_ctx {
  	int parent_id;
  	int child_id;
  	struct k_thread *parent;
  };
  
  static int thread_index_get(struct k_thread *t)
  {
  	struct _k_object *ko;
  
  	ko = _k_object_find(t);
  
  	if (!ko) {
  		return -1;
  	}
  
  	return ko->data;
  }
  
  static void wordlist_cb(struct _k_object *ko, void *ctx_ptr)
  {
  	struct perm_ctx *ctx = (struct perm_ctx *)ctx_ptr;
  
  	if (sys_bitfield_test_bit((mem_addr_t)&ko->perms, ctx->parent_id) &&
  				  (struct k_thread *)ko->name != ctx->parent) {
  		sys_bitfield_set_bit((mem_addr_t)&ko->perms, ctx->child_id);
  	}
  }
  
  void _thread_perms_inherit(struct k_thread *parent, struct k_thread *child)
  {
  	struct perm_ctx ctx = {
  		thread_index_get(parent),
  		thread_index_get(child),
  		parent
  	};
  
  	if ((ctx.parent_id != -1) && (ctx.child_id != -1)) {
  		_k_object_wordlist_foreach(wordlist_cb, &ctx);
  	}
  }
  
  void _thread_perms_set(struct _k_object *ko, struct k_thread *thread)
  {
  	int index = thread_index_get(thread);
  
  	if (index != -1) {
  		sys_bitfield_set_bit((mem_addr_t)&ko->perms, index);
  	}
  }
  
  void _thread_perms_clear(struct _k_object *ko, struct k_thread *thread)
  {
  	int index = thread_index_get(thread);
  
  	if (index != -1) {
  		sys_bitfield_clear_bit((mem_addr_t)&ko->perms, index);
  	}
  }
  
  static void clear_perms_cb(struct _k_object *ko, void *ctx_ptr)
  {
  	int id = (int)ctx_ptr;
  
  	sys_bitfield_clear_bit((mem_addr_t)&ko->perms, id);
  }
  
  void _thread_perms_all_clear(struct k_thread *thread)
  {
  	int index = thread_index_get(thread);
  
  	if (index != -1) {
  		_k_object_wordlist_foreach(clear_perms_cb, (void *)index);
  	}
  }
  
  static int thread_perms_test(struct _k_object *ko)
  {
  	int index;
  
  	if (ko->flags & K_OBJ_FLAG_PUBLIC) {
  		return 1;
  	}
  
  	index = thread_index_get(_current);
  	if (index != -1) {
  		return sys_bitfield_test_bit((mem_addr_t)&ko->perms, index);
  	}
  	return 0;
  }
  
  static void dump_permission_error(struct _k_object *ko)
  {
  	int index = thread_index_get(_current);
  	printk("thread %p (%d) does not have permission on %s %p [",
  	       _current, index,
  	       otype_to_str(ko->type), ko->name);
  	for (int i = CONFIG_MAX_THREAD_BYTES - 1; i >= 0; i--) {
  		printk("%02x", ko->perms[i]);
  	}
  	printk("]\n");
  }
  
  void _dump_object_error(int retval, void *obj, struct _k_object *ko,
  			enum k_objects otype)
  {
  	switch (retval) {
  	case -EBADF:
  		printk("%p is not a valid %s\n", obj, otype_to_str(otype));
  		break;
  	case -EPERM:
  		dump_permission_error(ko);
  		break;
  	case -EINVAL:
  		printk("%p used before initialization\n", obj);
  		break;
  	case -EADDRINUSE:
  		printk("%p %s in use\n", obj, otype_to_str(otype));
  	}
  }
  
  void _impl_k_object_access_grant(void *object, struct k_thread *thread)
  {
  	struct _k_object *ko = _k_object_find(object);
  
  	if (ko) {
  		_thread_perms_set(ko, thread);
  	}
  }
  
  void _impl_k_object_access_revoke(void *object, struct k_thread *thread)
  {
  	struct _k_object *ko = _k_object_find(object);
  
  	if (ko) {
  		_thread_perms_clear(ko, thread);
  	}
  }
  
  void k_object_access_all_grant(void *object)
  {
  	struct _k_object *ko = _k_object_find(object);
  
  	if (ko) {
  		ko->flags |= K_OBJ_FLAG_PUBLIC;
  	}
  }
  
  int _k_object_validate(struct _k_object *ko, enum k_objects otype,
  		       enum _obj_init_check init)
  {
  	if (unlikely(!ko || (otype != K_OBJ_ANY && ko->type != otype))) {
  		return -EBADF;
  	}
  
  	/* Manipulation of any kernel objects by a user thread requires that
  	 * thread be granted access first, even for uninitialized objects
  	 */
  	if (unlikely(!thread_perms_test(ko))) {
  		return -EPERM;
  	}
  
  	/* Initialization state checks. _OBJ_INIT_ANY, we don't care */
  	if (likely(init == _OBJ_INIT_TRUE)) {
  		/* Object MUST be intialized */
  		if (unlikely(!(ko->flags & K_OBJ_FLAG_INITIALIZED))) {
  			return -EINVAL;
  		}
  	} else if (init < _OBJ_INIT_TRUE) { /* _OBJ_INIT_FALSE case */
  		/* Object MUST NOT be initialized */
  		if (unlikely(ko->flags & K_OBJ_FLAG_INITIALIZED)) {
  			return -EADDRINUSE;
  		}
  	}
  
  	return 0;
  }
  
  void _k_object_init(void *object)
  {
  	struct _k_object *ko;
  
  	/* By the time we get here, if the caller was from userspace, all the
  	 * necessary checks have been done in _k_object_validate(), which takes
  	 * place before the object is initialized.
  	 *
  	 * This function runs after the object has been initialized and
  	 * finalizes it
  	 */
  
  	ko = _k_object_find(object);
  	if (!ko) {
  		/* Supervisor threads can ignore rules about kernel objects
  		 * and may declare them on stacks, etc. Such objects will never
  		 * be usable from userspace, but we shouldn't explode.
  		 */
  		return;
  	}
  
  	/* Allows non-initialization system calls to be made on this object */
  	ko->flags |= K_OBJ_FLAG_INITIALIZED;
  }
  
  void _k_object_uninit(void *object)
  {
  	struct _k_object *ko;
  
  	/* See comments in _k_object_init() */
  	ko = _k_object_find(object);
  	if (!ko) {
  		return;
  	}
  
  	ko->flags &= ~K_OBJ_FLAG_INITIALIZED;
  }
  
  static u32_t _handler_bad_syscall(u32_t bad_id, u32_t arg2, u32_t arg3,
  				  u32_t arg4, u32_t arg5, u32_t arg6, void *ssf)
  {
  	printk("Bad system call id %u invoked\n", bad_id);
  	_arch_syscall_oops(ssf);
  	CODE_UNREACHABLE;
  }
  
  static u32_t _handler_no_syscall(u32_t arg1, u32_t arg2, u32_t arg3,
  				 u32_t arg4, u32_t arg5, u32_t arg6, void *ssf)
  {
  	printk("Unimplemented system call\n");
  	_arch_syscall_oops(ssf);
  	CODE_UNREACHABLE;
  }
  
  #include <syscall_dispatch.c>
  
  