160 lines
4.6 KiB
C
160 lines
4.6 KiB
C
#include <kernel/process.h>
|
|
#include <asm/unistd_32.h>
|
|
#include <kernel/memory.h>
|
|
#include <kernel/devices/earlyterm.h>
|
|
#include <kernel/fs/vfs.h>
|
|
#include <sys/signal.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
/* proc_stacks_create() - create user and kernel stack */
|
|
static int proc_stacks_create(struct process *proc)
|
|
{
|
|
// Initialize user stack
|
|
proc->memory.stack.size.user = PROCESS_USER_STACK_SIZE;
|
|
proc->memory.stack.user = pm_pages_alloc(PM_SIZE_TO_PAGES(proc->memory.stack.size.user));
|
|
if (proc->memory.stack.user == NULL)
|
|
{
|
|
earlyterm_write("proc_error: user stack error !");
|
|
DBG_WAIT;
|
|
process_free(proc);
|
|
return (-1);
|
|
}
|
|
proc->context.reg[15] = (uint32_t)proc->memory.stack.user + proc->memory.stack.size.user;
|
|
|
|
// Initialize kernel stack
|
|
proc->memory.stack.size.kernel = PROCESS_KERNEL_STACK_SIZE;
|
|
proc->memory.stack.kernel = pm_pages_alloc(PM_SIZE_TO_PAGES(proc->memory.stack.size.kernel));
|
|
if (proc->memory.stack.kernel == NULL)
|
|
{
|
|
earlyterm_write("proc_error: kernel stack error !");
|
|
DBG_WAIT;
|
|
pm_pages_free((void *)proc->memory.stack.user);
|
|
process_free(proc);
|
|
return (-1);
|
|
}
|
|
proc->stack.kernel = proc->memory.stack.kernel + proc->memory.stack.size.kernel;
|
|
return (0);
|
|
}
|
|
|
|
/* proc_exit_inject() - inject "exit" procedure (involved at main()'s returning) */
|
|
static int proc_exit_inject(struct process *proc)
|
|
{
|
|
uint8_t callexit[8] = {
|
|
0b01100100, 0b00000011, // mov r0, r4
|
|
0b11000011, __NR_exit, // trapa #__NR_exit
|
|
0b10110000, 0b00000100, // bsr PC + 2 - 4
|
|
0b00000000, 0b00001001 // nop
|
|
};
|
|
|
|
// Inject exit procedure
|
|
memcpy(proc->memory.stack.user, callexit, 8);
|
|
proc->context.pr = (uint32_t)proc->memory.stack.user;
|
|
return (0);
|
|
}
|
|
|
|
/* proc_context_init() - Initialise first program context */
|
|
static void proc_context_init(struct process *proc)
|
|
{
|
|
// Initialize context.
|
|
for (int i = 0 ; i < 15 ; i = i + 1)
|
|
proc->context.reg[i] = 0x00000000;
|
|
|
|
// Initialize "special" registers.
|
|
proc->context.gbr = 0x00000000;
|
|
proc->context.macl = 0x00000000;
|
|
proc->context.mach = 0x00000000;
|
|
proc->context.ssr = 0x40000000; // <- force privilegied mode !
|
|
proc->context.spc = 0x00000000;
|
|
}
|
|
|
|
/* proc_file_init() - Initialize file part */
|
|
static void proc_file_init(struct process *proc)
|
|
{
|
|
extern struct dentry *vfs_root_node;
|
|
|
|
// Initialise file cache
|
|
for (int i = 0 ; i < PROCESS_NB_OPEN_FILE ; i = i + 1)
|
|
{
|
|
proc->opfile[i].status = PROCESS_FILE_SLOT_UNUSED;
|
|
proc->opfile[i].file.private = NULL;
|
|
proc->opfile[i].file.file_op = NULL;
|
|
proc->opfile[i].file.permission = 0;
|
|
proc->opfile[i].file.cursor = 0;
|
|
}
|
|
|
|
// Initialize working directory path
|
|
proc->working_dir = vfs_root_node;
|
|
|
|
// Open TTY for stdin, stdout, stderr
|
|
// TODO: add correct stderr configurations
|
|
// TODO: do not open TTY each time ?
|
|
vfs_open(&proc->opfile[STDIN_FILENO].file, "/dev/tty", O_RDWR);
|
|
vfs_open(&proc->opfile[STDOUT_FILENO].file, "/dev/tty", O_RDWR);
|
|
vfs_open(&proc->opfile[STDERR_FILENO].file, "/dev/tty", O_RDWR);
|
|
proc->opfile[STDIN_FILENO].status = PROCESS_FILE_SLOT_USED;
|
|
proc->opfile[STDOUT_FILENO].status = PROCESS_FILE_SLOT_USED;
|
|
proc->opfile[STDERR_FILENO].status = PROCESS_FILE_SLOT_USED;
|
|
}
|
|
|
|
/* proc_signal_init() - Initialize signal management */
|
|
static void proc_signal_init(struct process *proc)
|
|
{
|
|
// Default value
|
|
for (int i = 0 ; i < NSIG ; ++i)
|
|
proc->signal[i] = __SIGUNDEF;
|
|
|
|
// Init pending and blocked signals
|
|
proc->sig_blocked = 0x00000000;
|
|
proc->sig_pending = 0x00000000;
|
|
|
|
// Initialize signals handled
|
|
proc->signal[SIGSTOP] = SIG_DFL;
|
|
proc->signal[SIGCONT] = SIG_DFL;
|
|
proc->signal[SIGCHLD] = SIG_DFL;
|
|
proc->signal[SIGTERM] = SIG_DFL;
|
|
proc->signal[SIGKILL] = SIG_DFL;
|
|
proc->signal[SIGSEGV] = SIG_DFL;
|
|
proc->signal[SIGINT] = SIG_DFL;
|
|
proc->signal[SIGHUP] = SIG_IGN;
|
|
proc->signal[SIGFPE] = SIG_DFL;
|
|
}
|
|
|
|
struct process *process_create(void)
|
|
{
|
|
extern struct process *process_current;
|
|
struct process *process;
|
|
|
|
// Try to initialise new process
|
|
process = process_alloc();
|
|
if (process == NULL
|
|
|| proc_stacks_create(process) != 0
|
|
|| proc_exit_inject(process) != 0) {
|
|
earlyterm_write("proc_error: alloc error !");
|
|
return (NULL);
|
|
}
|
|
|
|
// Initialise internal process part
|
|
proc_context_init(process);
|
|
proc_file_init(process);
|
|
proc_signal_init(process);
|
|
|
|
// Initialize heap
|
|
process->memory.heap = NULL;
|
|
|
|
// Initialize internal data
|
|
process->sched_task = NULL;
|
|
process->__stat_loc = 0x00000000;
|
|
|
|
// Link new process with his parent.
|
|
// @Note:
|
|
// But de not link praent with new
|
|
// process to avoid crash with sheduler.
|
|
// The new process will be visible only
|
|
// when it is registered by the sheduler.
|
|
process->parent = process_current;
|
|
process->sibling = NULL;
|
|
process->child = NULL;
|
|
return (process);
|
|
}
|