402 lines
13 KiB
C
402 lines
13 KiB
C
|
/* Copyright (C) 2005 David Decotigny
|
||
|
Copyright (C) 2000-2004, The KOS team
|
||
|
|
||
|
This program is free software; you can redistribute it and/or
|
||
|
modify it under the terms of the GNU General Public License
|
||
|
as published by the Free Software Foundation; either version 2
|
||
|
of the License, or (at your option) any later version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with this program; if not, write to the Free Software
|
||
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||
|
USA.
|
||
|
*/
|
||
|
#ifndef _SOS_CPUCTXT_H_
|
||
|
#define _SOS_CPUCTXT_H_
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @file cpu_context.h
|
||
|
*
|
||
|
* Low level API to manage kernel and user thread CPU contexts. Should
|
||
|
* be some kind of architecture-independent.
|
||
|
*/
|
||
|
|
||
|
#include <sos/types.h>
|
||
|
#include <sos/errno.h>
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Prepare the system to deal with multiple CPU execution contexts
|
||
|
*/
|
||
|
sos_ret_t sos_cpu_context_subsystem_setup();
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Opaque structure storing the CPU context of an inactive kernel or
|
||
|
* user thread, as saved by the low level primitives below or by the
|
||
|
* interrupt/exception handlers.
|
||
|
*
|
||
|
* @note This is an (architecture-independent) forward declaration:
|
||
|
* see cpu_context.c and the *.S files for its
|
||
|
* (architecture-dependent) definition.
|
||
|
*/
|
||
|
struct sos_cpu_state;
|
||
|
|
||
|
|
||
|
/**
|
||
|
* The type of the functions passed as arguments to the Kernel thread
|
||
|
* related functions.
|
||
|
*/
|
||
|
typedef void (sos_cpu_kstate_function_arg1_t(sos_ui32_t arg1));
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Function to create an initial context for a kernel thread starting
|
||
|
* its execution at function start_func with the argument initial_arg,
|
||
|
* and having the stack defined by stack_bottom/stack_size. When the
|
||
|
* start_func function returns, the function exit_func is called with
|
||
|
* argument exit_arg.
|
||
|
*
|
||
|
* @param kctxt The kernel thread CPU context to initialize. The
|
||
|
* address of the newly-initialized struct sos_cpu_state will be
|
||
|
* stored in this variable. The contents of this struct sos_cpu_state
|
||
|
* are actually located /inside/ the stack.
|
||
|
*
|
||
|
* @param start_func The address of the first instruction that will be
|
||
|
* executed when this context will be first transferred on
|
||
|
* CPU. Practically speaking, this is the address of a function that
|
||
|
* is assumed to take 1 argument.
|
||
|
*
|
||
|
* @param start_arg The value that will be passed as the argument to
|
||
|
* start_func when the thread starts. The stack will be setup
|
||
|
* accordingly to simulate a real call to the function and really
|
||
|
* passing this arguement.
|
||
|
*
|
||
|
* @param stack_bottom The lowest address of the stack.
|
||
|
*
|
||
|
* @param stack_size The size of the stack.
|
||
|
*
|
||
|
* @param exit_func The address of the instruction executed after the
|
||
|
* function start_func has returned. This function takes 1 parameter
|
||
|
* as argument: exit_arg.
|
||
|
*
|
||
|
* @param exit_arg The argument passed to the function exit_func.
|
||
|
*
|
||
|
* @note the newly created context is INTERRUPTIBLE by default !
|
||
|
*/
|
||
|
sos_ret_t sos_cpu_kstate_init(struct sos_cpu_state **kctxt,
|
||
|
sos_cpu_kstate_function_arg1_t *start_func,
|
||
|
sos_ui32_t start_arg,
|
||
|
sos_vaddr_t stack_bottom,
|
||
|
sos_size_t stack_size,
|
||
|
sos_cpu_kstate_function_arg1_t *exit_func,
|
||
|
sos_ui32_t exit_arg);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Function to create an initial context for a user thread starting
|
||
|
* its execution at function user_start_PC with the user_start_arg
|
||
|
* argument. The address of the user stack before any modification by
|
||
|
* the ustate_init() function is given by user_start_SP. The user
|
||
|
* thread starts in user space first and needs a kernel stack for
|
||
|
* the syscalls and for handling interrupts: the address of this
|
||
|
* kernel stack is given by the kernel_stack_* parameters.
|
||
|
*
|
||
|
* @param uctxt The user thread CPU context to initialize. The
|
||
|
* address of the newly-initialized struct sos_cpu_state will be
|
||
|
* stored in this variable. The contents of this struct sos_cpu_state
|
||
|
* are actually located /inside/ the kernel stack of the thread.
|
||
|
*
|
||
|
* @param user_start_PC The address of the first instruction that will
|
||
|
* be executed in user mode when this context will be first
|
||
|
* transferred on CPU. Practically speaking, this is the address of a
|
||
|
* function that is assumed to take 1 argument.
|
||
|
*
|
||
|
* @param user_start_SP The initial user stack address.
|
||
|
*
|
||
|
* @param user_start_argX The 2 parameters passed to the initial user
|
||
|
* thread function (in registers).
|
||
|
*
|
||
|
* @param kernel_stack_bottom The lowest address of the kernel stack
|
||
|
* used to switch to user mode and to handle interrupts/exceptions.
|
||
|
*
|
||
|
* @param kernel_stack_size The size of the kernel stack (@see
|
||
|
* kernel_stack_bottom).
|
||
|
*
|
||
|
* @note the newly thread context is INTERRUPTIBLE !
|
||
|
*/
|
||
|
sos_ret_t sos_cpu_ustate_init(struct sos_cpu_state **uctxt,
|
||
|
sos_uaddr_t user_start_PC,
|
||
|
sos_ui32_t user_start_arg1,
|
||
|
sos_ui32_t user_start_arg2,
|
||
|
sos_uaddr_t user_initial_SP,
|
||
|
sos_vaddr_t kernel_stack_bottom,
|
||
|
sos_size_t kernel_stack_size);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Function that performs an immediate context-switch from one
|
||
|
* kernel/user thread to another one. It stores the current executing
|
||
|
* context in from_ctxt, and restores to_context on CPU.
|
||
|
*
|
||
|
* @param from_ctxt The address of the struct sos_cpu_state will be
|
||
|
* stored in this variable. Must NOT be NULL.
|
||
|
*
|
||
|
* @param to_ctxt The CPU will resume its execution with the struct
|
||
|
* sos_cpu_state located at this address. Must NOT be NULL.
|
||
|
*/
|
||
|
void sos_cpu_context_switch(struct sos_cpu_state **from_ctxt,
|
||
|
struct sos_cpu_state *to_ctxt);
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Switch to the new given context (of a kernel/user thread) without
|
||
|
* saving the old context (of another kernel/user thread), and call
|
||
|
* the function reclaiming_func passing it the recalining_arg
|
||
|
* argument. The reclaining function is called from within the stack
|
||
|
* of the new context, so that it can (among other things) safely
|
||
|
* destroy the stack of the former context.
|
||
|
*
|
||
|
* @param switch_to_ctxt The context that will be restored on the CPU
|
||
|
*
|
||
|
* @param reclaiming_func The address of the function that will be
|
||
|
* called after having changed the stack, but before restoring the CPU
|
||
|
* context to switch_to_ctxt.
|
||
|
*/
|
||
|
void
|
||
|
sos_cpu_context_exit_to(struct sos_cpu_state *switch_to_ctxt,
|
||
|
sos_cpu_kstate_function_arg1_t *reclaiming_func,
|
||
|
sos_ui32_t reclaiming_arg) __attribute__((noreturn));
|
||
|
|
||
|
/* =======================================================================
|
||
|
* Public Accessor functions
|
||
|
*/
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Return whether the saved context was in kernel or user context
|
||
|
*
|
||
|
* @return TRUE when context was interrupted when in user mode, FALSE
|
||
|
* when in kernel mode, < 0 on error.
|
||
|
*/
|
||
|
sos_ret_t
|
||
|
sos_cpu_context_is_in_user_mode(const struct sos_cpu_state *ctxt);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Return Program Counter stored in the saved kernel/user context
|
||
|
*/
|
||
|
sos_vaddr_t sos_cpu_context_get_PC(const struct sos_cpu_state *ctxt);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Return Stack Pointer stored in the saved kernel/user context
|
||
|
*/
|
||
|
sos_vaddr_t sos_cpu_context_get_SP(const struct sos_cpu_state *ctxt);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Dump the contents of the CPU context (bochs + x86_videomem)
|
||
|
*/
|
||
|
void sos_cpu_context_dump(const struct sos_cpu_state *ctxt);
|
||
|
|
||
|
|
||
|
/* =======================================================================
|
||
|
* Public Accessor functions TO BE USED ONLY BY Exception handlers
|
||
|
*/
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Return the argument passed by the CPU upon exception, as stored in the
|
||
|
* saved context
|
||
|
*/
|
||
|
sos_ui32_t sos_cpu_context_get_EX_info(const struct sos_cpu_state *ctxt);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Return the faulting address of the exception
|
||
|
*/
|
||
|
sos_vaddr_t
|
||
|
sos_cpu_context_get_EX_faulting_vaddr(const struct sos_cpu_state *ctxt);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Change the return address of the given context
|
||
|
*/
|
||
|
sos_ret_t
|
||
|
sos_cpu_context_set_EX_return_address(struct sos_cpu_state *ctxt,
|
||
|
sos_vaddr_t ret_vaddr);
|
||
|
|
||
|
|
||
|
/* =======================================================================
|
||
|
* Public Accessor functions TO BE USED ONLY BY the SYSCALL handler
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* Low-level functions used by the syscall handler. They are
|
||
|
* responsible for retrieving the arguments passed to the syscall when
|
||
|
* a user thread makes a syscall. Some of these arguments are
|
||
|
* available as registers' values in the user context, some of them
|
||
|
* are user-space addresses given by these registers.
|
||
|
*
|
||
|
* @return SOS_OK on success, <0 otherwise
|
||
|
*/
|
||
|
sos_ret_t sos_syscall_get1arg(const struct sos_cpu_state *user_ctxt,
|
||
|
/* out */unsigned int *arg1);
|
||
|
|
||
|
sos_ret_t sos_syscall_get2args(const struct sos_cpu_state *user_ctxt,
|
||
|
/* out */unsigned int *arg1,
|
||
|
/* out */unsigned int *arg2);
|
||
|
|
||
|
sos_ret_t sos_syscall_get3args(const struct sos_cpu_state *user_ctxt,
|
||
|
/* out */unsigned int *arg1,
|
||
|
/* out */unsigned int *arg2,
|
||
|
/* out */unsigned int *arg3);
|
||
|
|
||
|
sos_ret_t sos_syscall_get4args(const struct sos_cpu_state *user_ctxt,
|
||
|
/* out */unsigned int *arg1,
|
||
|
/* out */unsigned int *arg2,
|
||
|
/* out */unsigned int *arg3,
|
||
|
/* out */unsigned int *arg4);
|
||
|
|
||
|
sos_ret_t sos_syscall_get5args(const struct sos_cpu_state *user_ctxt,
|
||
|
/* out */unsigned int *arg1,
|
||
|
/* out */unsigned int *arg2,
|
||
|
/* out */unsigned int *arg3,
|
||
|
/* out */unsigned int *arg4,
|
||
|
/* out */unsigned int *arg5);
|
||
|
|
||
|
sos_ret_t sos_syscall_get6args(const struct sos_cpu_state *user_ctxt,
|
||
|
/* out */unsigned int *arg1,
|
||
|
/* out */unsigned int *arg2,
|
||
|
/* out */unsigned int *arg3,
|
||
|
/* out */unsigned int *arg4,
|
||
|
/* out */unsigned int *arg5,
|
||
|
/* out */unsigned int *arg6);
|
||
|
|
||
|
sos_ret_t sos_syscall_get7args(const struct sos_cpu_state *user_ctxt,
|
||
|
/* out */unsigned int *arg1,
|
||
|
/* out */unsigned int *arg2,
|
||
|
/* out */unsigned int *arg3,
|
||
|
/* out */unsigned int *arg4,
|
||
|
/* out */unsigned int *arg5,
|
||
|
/* out */unsigned int *arg6,
|
||
|
/* out */unsigned int *arg7);
|
||
|
|
||
|
sos_ret_t sos_syscall_get8args(const struct sos_cpu_state *user_ctxt,
|
||
|
/* out */unsigned int *arg1,
|
||
|
/* out */unsigned int *arg2,
|
||
|
/* out */unsigned int *arg3,
|
||
|
/* out */unsigned int *arg4,
|
||
|
/* out */unsigned int *arg5,
|
||
|
/* out */unsigned int *arg6,
|
||
|
/* out */unsigned int *arg7,
|
||
|
/* out */unsigned int *arg8);
|
||
|
|
||
|
|
||
|
/* =======================================================================
|
||
|
* Macros controlling stack poisoning.
|
||
|
* Stack poisoning can be used to detect:
|
||
|
* - unitialized local variables
|
||
|
* - when the thread might have gone too deep in the stack
|
||
|
*/
|
||
|
/** The signature of the poison */
|
||
|
#define SOS_CPU_STATE_STACK_POISON 0xa5
|
||
|
|
||
|
/**
|
||
|
* When set, mean that the whole stack is poisoned to detect use of
|
||
|
* unititialized variables
|
||
|
*/
|
||
|
#define SOS_CPU_STATE_DETECT_UNINIT_KERNEL_VARS
|
||
|
/* #undef SOS_CPU_STATE_DETECT_UNINIT_KERNEL_VARS */
|
||
|
|
||
|
/**
|
||
|
* When set, mean that the bottom of the stack is poisoned to detect
|
||
|
* probable stack overflow. Its value indicates the number of bytes
|
||
|
* used for this detection.
|
||
|
*/
|
||
|
#define SOS_CPU_STATE_DETECT_KERNEL_STACK_OVERFLOW 64
|
||
|
/* #undef SOS_CPU_STATE_DETECT_KERNEL_STACK_OVERFLOW */
|
||
|
|
||
|
#if defined(SOS_CPU_STATE_DETECT_KERNEL_STACK_OVERFLOW)
|
||
|
void
|
||
|
sos_cpu_state_prepare_detect_kernel_stack_overflow(const struct sos_cpu_state *ctxt,
|
||
|
sos_vaddr_t kernel_stack_bottom,
|
||
|
sos_size_t kernel_stack_size);
|
||
|
void sos_cpu_state_detect_kernel_stack_overflow(const struct sos_cpu_state *ctxt,
|
||
|
sos_vaddr_t kernel_stack_bottom,
|
||
|
sos_size_t kernel_stack_size);
|
||
|
#else
|
||
|
# define sos_cpu_state_prepare_detect_kernel_stack_overflow(ctxt,stkbottom,stksize) \
|
||
|
({ /* nop */ })
|
||
|
# define sos_cpu_state_detect_kernel_stack_overflow(ctxt,stkbottom,stksize) \
|
||
|
({ /* nop */ })
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/* =======================================================================
|
||
|
* Backtrace facility. To be used for DEBUGging purpose ONLY.
|
||
|
*/
|
||
|
|
||
|
|
||
|
/**
|
||
|
* The function called at each step of the backtrace iterations
|
||
|
*
|
||
|
* @param PC The address of the next instruction of the function that
|
||
|
* will be executed
|
||
|
*
|
||
|
* @param params The address of the array of the parameteres that have
|
||
|
* been passed to the function considered
|
||
|
*
|
||
|
* @param depth The index of the iteration (ie the depth of the
|
||
|
* current frame into the stack)
|
||
|
*
|
||
|
* @param custom_arg Whatever you want: this is the argument passed as
|
||
|
* custom_arg to sos_backtrace()
|
||
|
*/
|
||
|
typedef void (sos_backtrace_callback_t)(sos_vaddr_t PC,
|
||
|
sos_vaddr_t params,
|
||
|
sos_ui32_t depth,
|
||
|
void *custom_arg);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Call the backtracer callback on each frame stored in the cpu_state
|
||
|
*
|
||
|
* @param cpu_state The CPU context we want to explore. MUST be the
|
||
|
* context of a thread in Kernel mode, or NULL. When NULL: backtrace
|
||
|
* the current CPU context.
|
||
|
*
|
||
|
* @param max_depth The maximum number of frames to explore
|
||
|
*
|
||
|
* @param stack_bottom The lower boundary of the stack. This is used
|
||
|
* to make sure that the frame addresses fit inside the stack
|
||
|
* boudaries (ie are potentially correct).
|
||
|
*
|
||
|
* @param stack_size The size of the stack. Same comment.
|
||
|
*
|
||
|
* @param backtracer The function to call to handle the frame for each
|
||
|
* iteration
|
||
|
*
|
||
|
* @param custom_arg The arg passed as custom_arg to the backtracer
|
||
|
*
|
||
|
* @return The number of frames explored.
|
||
|
*
|
||
|
* @note Might be inaccurate when gcc's -fomit-frame-pointer has been
|
||
|
* used.
|
||
|
*/
|
||
|
sos_ui32_t sos_backtrace(const struct sos_cpu_state *cpu_state,
|
||
|
sos_ui32_t max_depth,
|
||
|
sos_vaddr_t stack_bottom,
|
||
|
sos_size_t stack_size,
|
||
|
sos_backtrace_callback_t * backtracer,
|
||
|
void *custom_arg);
|
||
|
|
||
|
#endif /* _SOS_CPUCTXT_H_ */
|