From d0a0f338c7ee8148d61ececa076e4659676305ed Mon Sep 17 00:00:00 2001 From: Enrico Fraccaroli Date: Wed, 10 Nov 2021 14:07:14 +0100 Subject: [PATCH] Add helper functions to handle the stack. --- mentos/inc/kernel.h | 3 -- mentos/inc/klib/stack_helper.h | 18 +++++++ mentos/src/process/process.c | 93 +++++++++++++++++++--------------- mentos/src/system/signal.c | 7 +-- 4 files changed, 73 insertions(+), 48 deletions(-) create mode 100644 mentos/inc/klib/stack_helper.h diff --git a/mentos/inc/kernel.h b/mentos/inc/kernel.h index 52238c6..320953e 100644 --- a/mentos/inc/kernel.h +++ b/mentos/inc/kernel.h @@ -11,9 +11,6 @@ /// @brief The initial stack pointer. extern uintptr_t initial_esp; -/// @brief Push the `item` of a given `type` on the `stack`. -#define PUSH_ARG(stack, type, item) (*((type *)((stack) -= sizeof(type))) = (item)) - /// Kilobytes. #define K 1024 /// Megabytes. diff --git a/mentos/inc/klib/stack_helper.h b/mentos/inc/klib/stack_helper.h new file mode 100644 index 0000000..ea6dff3 --- /dev/null +++ b/mentos/inc/klib/stack_helper.h @@ -0,0 +1,18 @@ +/// MentOS, The Mentoring Operating system project +/// @file stack_helper.h +/// @brief Couple of macros that help accessing the stack. +/// @copyright (c) 2014-2021 This file is distributed under the MIT License. +/// See LICENSE.md for details. + +#pragma once + +/// @brief Access the value of the pointer. +#define __ACCESS_PTR(type, ptr) (*(type *)(ptr)) +/// @brief Moves the pointer down. +#define __MOVE_PTR_DOWN(type, ptr) ((ptr) -= sizeof(type)) +/// @brief Moves the pointer up. +#define __MOVE_PTR_UP(type, ptr) ((ptr) += sizeof(type)) +/// @brief First, it moves the pointer down, and then it pushes the value at that memory location. +#define PUSH_VALUE_ON_STACK(ptr, value) (__ACCESS_PTR(typeof(value), __MOVE_PTR_DOWN(typeof(value), ptr)) = (value)) +/// @brief First, it access the value at the given memory location, and then it moves the pointer up. +#define POP_VALUE_FROM_STACK(value, ptr) ({value = __ACCESS_PTR(typeof(value), ptr); __MOVE_PTR_UP(typeof(value), ptr); }) diff --git a/mentos/src/process/process.c b/mentos/src/process/process.c index a947429..a79112a 100644 --- a/mentos/src/process/process.c +++ b/mentos/src/process/process.c @@ -4,7 +4,6 @@ /// @copyright (c) 2014-2021 This file is distributed under the MIT License. /// See LICENSE.md for details. - #include "sys/kernel_levels.h" //#ifndef __DEBUG_LEVEL__ @@ -25,37 +24,62 @@ #include "process/prio.h" #include "fs/vfs.h" #include "elf/elf.h" +#include "klib/stack_helper.h" /// Cache for creating the task structs. static kmem_cache_t *task_struct_cache; /// @brief The task_struct of the init process. static task_struct *init_proc; -static inline int __push_args_on_stack(uintptr_t *esp, char *args[], char ***argsptr) +/// @brief Counts the number of arguments. +/// @param args the array of arguments, it must be NULL terminated. +/// @return the number of arguments. +static inline int __count_args(char **args) { int argc = 0; - char *args_ptr[256]; - // Count the number of arguments. - while (args[argc] != NULL) { + while (args[argc] != NULL) ++argc; - } + return argc; +} +/// @brief Counts the bytes occupied by the arguments. +/// @param args the array of arguments, it must be NULL terminated. +/// @return the bytes occupied by the arguments. +static inline int __count_args_bytes(char **args) +{ + // Count the number of arguments. + int argc = __count_args(args); + // Count the number of characters. + int nchar = 0; + for (int i = 0; i < argc; i++) { + nchar += strlen(args[i]) + 1; + } + return nchar + (argc + 1 /* The NULL terminator */) * sizeof(char *); +} + +/// @brief Pushes the arguments on the stack. +/// @param stack pointer to the stack location. +/// @param args the list of arguments. +/// @return the final position of the stack, where the list of pushed arguments is stored. +static inline char **__push_args_on_stack(uintptr_t *stack, char *args[]) +{ + // Count the number of arguments. + int argc = __count_args(args); // Prepare args with space for the terminating NULL. + char *args_location[256]; for (int i = argc - 1; i >= 0; --i) { for (int j = strlen(args[i]); j >= 0; --j) { - PUSH_ARG((*esp), char, args[i][j]); + PUSH_VALUE_ON_STACK(*stack, args[i][j]); } - args_ptr[i] = (char *)(*esp); + args_location[i] = (char *)(*stack); } // Push terminating NULL. - PUSH_ARG((*esp), char *, (char *)NULL); + PUSH_VALUE_ON_STACK(*stack, (char *)NULL); // Push array of pointers to the arguments. for (int i = argc - 1; i >= 0; --i) { - PUSH_ARG((*esp), char *, args_ptr[i]); + PUSH_VALUE_ON_STACK(*stack, args_location[i]); } - (*argsptr) = (char **)(*esp); - - return argc; + return (char **)(*stack); } static int __reset_process(task_struct *task) @@ -121,23 +145,6 @@ static int __load_executable(const char *path, task_struct *task, uint32_t *entr return ret; } -static inline int __count_args_bytes(char **args) -{ - int argc = 0; - int bytes = 0; - - // Count the number of arguments. - while (args[argc] != NULL) { - ++argc; - } - - for (int i = 0; i < argc; i++) { - bytes += strlen(args[i]) + 1; - } - - return bytes + (argc + 1 /* The NULL terminator */) * sizeof(char *); -} - static inline task_struct *__alloc_task(task_struct *source, task_struct *parent, const char *name) { // Create a new task_struct. @@ -292,19 +299,19 @@ task_struct *process_create_init(const char *path) // Save where the arguments start. init_proc->mm->arg_start = init_proc->thread.regs.useresp; // Push the arguments on the stack. - __push_args_on_stack(&init_proc->thread.regs.useresp, argv, &argv_ptr); + argv_ptr = __push_args_on_stack(&init_proc->thread.regs.useresp, argv); // Save where the arguments end. init_proc->mm->arg_end = init_proc->thread.regs.useresp; // Save where the environmental variables start. init_proc->mm->env_start = init_proc->thread.regs.useresp; // Push the environment on the stack. - __push_args_on_stack(&init_proc->thread.regs.useresp, envp, &envp_ptr); + envp_ptr = __push_args_on_stack(&init_proc->thread.regs.useresp, envp); // Save where the environmental variables end. init_proc->mm->env_end = init_proc->thread.regs.useresp; // Push the `main` arguments on the stack (argc, argv, envp). - PUSH_ARG(init_proc->thread.regs.useresp, char **, envp_ptr); - PUSH_ARG(init_proc->thread.regs.useresp, char **, argv_ptr); - PUSH_ARG(init_proc->thread.regs.useresp, int, argc); + PUSH_VALUE_ON_STACK(init_proc->thread.regs.useresp, envp_ptr); + PUSH_VALUE_ON_STACK(init_proc->thread.regs.useresp, argv_ptr); + PUSH_VALUE_ON_STACK(init_proc->thread.regs.useresp, argc); // Restore previous pgdir paging_switch_directory(crtdir); @@ -428,7 +435,9 @@ int sys_execve(pt_regs *f) // == COPY PROGRAM ARGUMENTS ============================================== // Copy argv and envp to kernel memory, because all the old process memory will be discarded. + int argc = __count_args(origin_argv); int argv_bytes = __count_args_bytes(origin_argv); + int envc = __count_args(origin_envp); int envp_bytes = __count_args_bytes(origin_envp); if ((argv_bytes < 0) || (envp_bytes < 0)) { pr_err("Failed to count required memory to store arguments and environment (%d + %d).\n", @@ -443,8 +452,8 @@ int sys_execve(pt_regs *f) } // Copy the arguments. uint32_t args_mem_ptr = (uint32_t)args_mem + (argv_bytes + envp_bytes); - __push_args_on_stack(&args_mem_ptr, origin_argv, &saved_argv); - __push_args_on_stack(&args_mem_ptr, origin_envp, &saved_envp); + saved_argv = __push_args_on_stack(&args_mem_ptr, origin_argv); + saved_envp = __push_args_on_stack(&args_mem_ptr, origin_envp); // Check the memory pointer. assert(args_mem_ptr == (uint32_t)args_mem); // ------------------------------------------------------------------------ @@ -468,17 +477,17 @@ int sys_execve(pt_regs *f) // Save where the arguments start. current->mm->arg_start = current->thread.regs.useresp; // Push the arguments on the stack. - int argc = __push_args_on_stack(¤t->thread.regs.useresp, saved_argv, &final_argv); + final_argv = __push_args_on_stack(¤t->thread.regs.useresp, saved_argv); // Save where the arguments end, and the env starts. current->mm->env_start = current->mm->arg_end = current->thread.regs.useresp; // Push the environment on the stack. - int envc = __push_args_on_stack(¤t->thread.regs.useresp, saved_envp, &final_envp); + final_envp = __push_args_on_stack(¤t->thread.regs.useresp, saved_envp); // Save where the environmental variables end. current->mm->env_end = current->thread.regs.useresp; // Push the `main` arguments on the stack (argc, argv, envp). - PUSH_ARG(current->thread.regs.useresp, char **, final_envp); - PUSH_ARG(current->thread.regs.useresp, char **, final_argv); - PUSH_ARG(current->thread.regs.useresp, int, argc); + PUSH_VALUE_ON_STACK(current->thread.regs.useresp, final_envp); + PUSH_VALUE_ON_STACK(current->thread.regs.useresp, final_argv); + PUSH_VALUE_ON_STACK(current->thread.regs.useresp, argc); // Restore previous pgdir paging_switch_directory(crtdir); diff --git a/mentos/src/system/signal.c b/mentos/src/system/signal.c index 9c133b8..a1efa81 100644 --- a/mentos/src/system/signal.c +++ b/mentos/src/system/signal.c @@ -16,6 +16,7 @@ #include "io/debug.h" #include "string.h" #include "klib/irqflags.h" +#include "klib/stack_helper.h" /// SLAB caches for signal bits. static kmem_cache_t *sigqueue_cachep; @@ -289,14 +290,14 @@ static inline int __handle_signal(int signr, siginfo_t *info, sigaction_t *ka, s // We push on the stack the entire siginfo. __copy_siginfo(siginfo_addr, info); // We push on the stack the pointer to the siginfo we copied on the stack. - PUSH_ARG(regs->useresp, siginfo_t *, siginfo_addr); + PUSH_VALUE_ON_STACK(regs->useresp, siginfo_addr); } // Push on the stack the signal number, first and only argument of the handler. - PUSH_ARG(regs->useresp, int, signr); + PUSH_VALUE_ON_STACK(regs->useresp, signr); // Push on the stack the function required to handle the signal return. - PUSH_ARG(regs->useresp, uint32_t, current->sigreturn_eip); + PUSH_VALUE_ON_STACK(regs->useresp, current->sigreturn_eip); return 1; }