Add helper functions to handle the stack.

This commit is contained in:
Enrico Fraccaroli
2021-11-10 14:07:14 +01:00
parent ca4250c663
commit d0a0f338c7
4 changed files with 73 additions and 48 deletions
-3
View File
@@ -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.
+18
View File
@@ -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); })
+51 -42
View File
@@ -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(&current->thread.regs.useresp, saved_argv, &final_argv);
final_argv = __push_args_on_stack(&current->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(&current->thread.regs.useresp, saved_envp, &final_envp);
final_envp = __push_args_on_stack(&current->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);
+4 -3
View File
@@ -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;
}