Esempio n. 1
0
/* delete a context */
void context_free(context_t *cont)
{
	/* we don't need to lock because this is called only when we free the context anyway */

	while (cont->funcs.next != NULL) {
		context_free_function(LIST_TO_STRUCT(function_t, list, cont->funcs.next));
	}
	while (cont->anonym.next != NULL) {
		context_free_function(LIST_TO_STRUCT(function_t, list, cont->anonym.next));
	}

	memory_free(cont);
}
Esempio n. 2
0
/* write callback */
static ssize_t kplugs_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
	kplugs_command_t *cmd = NULL;
	context_t *file_cont = NULL;
	context_t *cont = NULL;
	bytecode_t *code = NULL;
	function_t *func = NULL;
	exception_t excep;
	stack_t stack;
	word iter, arg;
	word args;
	byte little_endian;
	byte func_name[MAX_FUNC_NAME + 1];
	int err = 0;

#ifdef __LITTLE_ENDIAN
	little_endian = 1;
#else
	little_endian = 0;
#endif
	/* get the user's command */
	cmd = (kplugs_command_t *)buf;
	file_cont = (context_t *)filp->private_data;

	if (count < sizeof(byte) * 3) { /* three bytes of header */
		return create_error(file_cont, -ERROR_PARAM);
	}

	if (cmd->word_size != sizeof(word) || cmd->l_endian != little_endian) {
		return create_error(file_cont, -ERROR_ARCH);
	}

	if (cmd->version_major != VERSION_MAJOR || cmd->version_minor != VERSION_MINOR) {
		return create_error(file_cont, -ERROR_VERSION);
	}

	if (count != sizeof(kplugs_command_t)) {
		return create_error(file_cont, -ERROR_PARAM);
	}

	cont = cmd->is_global ? GLOBAL_CONTEXT : file_cont;

	switch (cmd->type) {
	case KPLUGS_LOAD:
		/* load a new function */

		if (cmd->len2 != 0 || cmd->ptr2 != NULL) {
			return create_error(file_cont, -ERROR_PARAM);
		}

		code = memory_alloc(cmd->len1);
		if (NULL == code) {
			ERROR(create_error(file_cont, -ERROR_MEM));
		}

		err = memory_copy_from_outside(code, cmd->uptr1, cmd->len1);
		if (err < 0) {
			err = create_error(file_cont, err);
			goto clean;
		}

		/* create the function */
		err = function_create(code, cmd->len1, &func);
		if (err < 0) {
			err = create_error(file_cont, err);
			goto clean;
		}

		err = context_add_function(cont, func);
		if (err < 0) {
			err = create_error(file_cont, err);
			goto clean;
		}

		/* return the function's address */
		context_create_reply(file_cont, (word)&func->func_code, NULL);

		return count;

	case KPLUGS_UNLOAD:
		/* unload a function with a name */
		if (NULL != cmd->uptr2) {
			return create_error(file_cont, -ERROR_PARAM);
		}
	case KPLUGS_EXECUTE:
		/* execute (and unload) a function with a name */
		if (cmd->len1 > MAX_FUNC_NAME || (cmd->len2 % sizeof(word)) != 0) {
			return create_error(file_cont, -ERROR_PARAM);
		}

		err = memory_copy_from_outside(func_name, cmd->uptr1, cmd->len1);
		if (err < 0) {
			return create_error(file_cont, err);
		}

		func_name[cmd->len1] = '\0';

		/* find the function */

		if (cmd->type == KPLUGS_UNLOAD) {
			func = context_find_function(cont, func_name);
			if (NULL == func) {
				return create_error(file_cont, -ERROR_UFUNC);
			}
			/* delete the function */
			context_free_function(func);
			err = (int)count;

			goto clean;
		}

		if (!cmd->is_global) {
			func = context_find_function(file_cont, func_name);
		}
		if (NULL == func) {
			func = context_find_function(GLOBAL_CONTEXT, func_name);
			if (NULL == func) {
				return create_error(file_cont, -ERROR_UFUNC);
			}
		}

		goto execute_func;

	case KPLUGS_UNLOAD_ANONYMOUS:
		/* unload an anonymous function */
		if (NULL != cmd->uptr2 || cmd->len1 || cmd->len2) {
			return create_error(file_cont, -ERROR_PARAM);
		}
		func = context_find_anonymous(cont, cmd->ptr1);
		if (NULL == func) {
			return create_error(file_cont, -ERROR_UFUNC);
		}

		/* delete the function */
		context_free_function(func);

		err = (int)count;
		goto clean;
	break;

	case KPLUGS_EXECUTE_ANONYMOUS:
		/* execute (and unload) an anonymous function */
		if (cmd->len1 || (cmd->len2 % sizeof(word)) != 0) {
			return create_error(file_cont, -ERROR_PARAM);
		}

		/* find the function */
		if (!cmd->is_global) {
			func = context_find_anonymous(file_cont, cmd->ptr1);
		}
		if (NULL == func) {
			func = context_find_anonymous(GLOBAL_CONTEXT, cmd->ptr1);
			if (NULL == func) {
				return create_error(file_cont, -ERROR_UFUNC);
			}
		}

execute_func:
		/* do the execution of a function: */

		args = cmd->len2 / sizeof(word);
		if (args > func->num_maxargs || args < func->num_minargs) {
			ERROR_CLEAN(create_error(file_cont, -ERROR_ARGS));
		}

		err = stack_alloc(&stack, sizeof(word), CALL_STACK_SIZE);
		if (err < 0) {
			err = create_error(file_cont, err);
			goto clean;
		}

		/* push the arguments to a stack */
		for (iter = 0; iter < args; ++iter) {
			err = memory_copy_from_outside(&arg, cmd->ptr2 + (iter * sizeof(word)), sizeof(arg));
			if (err < 0) {
				stack_free(&stack);
				err = create_error(file_cont, err);
				goto clean;
			}

			if (NULL == stack_push(&stack, &arg)) {
				stack_free(&stack);
				ERROR_CLEAN(create_error(file_cont, -ERROR_MEM));
			}
		}

		/* execute the function and create an answer */
		arg = vm_run_function(func, &stack, &excep);

		stack_free(&stack);

		if (excep.had_exception) {
			err = -EINVAL; /* it dosen't really matter which error. the value of the error will be taken from the answer */
			arg = excep.value;
		} else {
			err = (int)count;
		}

		context_create_reply(file_cont, arg, &excep);

		goto clean;

	case KPLUGS_GET_LAST_EXCEPTION:
		if (NULL != cmd->uptr2 || cmd->len1 < sizeof(exception_t) || cmd->len2) {
			ERROR(create_error(file_cont, -ERROR_PARAM));
		}

		err = context_get_last_exception(file_cont, (exception_t *)cmd->ptr1);
		if (err < 0) {
			return create_error(file_cont, err);
		}

		return count;

	default:
		return create_error(file_cont, -ERROR_PARAM);
	}
clean:
	if (NULL != func) {
		function_put(func);
	} else if (NULL != code) {
		memory_free(code);
	}
	return err;
}