Update MentOs code to the latest development version.
This commit is contained in:
@@ -1,22 +1,20 @@
|
||||
/// MentOS, The Mentoring Operating system project
|
||||
/// @file errno.c
|
||||
/// @brief
|
||||
/// @copyright (c) 2019 This file is distributed under the MIT License.
|
||||
/// @copyright (c) 2014-2021 This file is distributed under the MIT License.
|
||||
/// See LICENSE.md for details.
|
||||
|
||||
#include "errno.h"
|
||||
#include "scheduler.h"
|
||||
|
||||
/// @brief Returns the error number for the current process.
|
||||
/// @return Pointer to the error number.
|
||||
int *__geterrno()
|
||||
{
|
||||
static int _errno = 0;
|
||||
|
||||
task_struct *current_process = kernel_get_current_process();
|
||||
|
||||
if (current_process == NULL)
|
||||
{
|
||||
static int _errno = 0;
|
||||
task_struct *current_process = scheduler_get_current_process();
|
||||
if (current_process == NULL) {
|
||||
return &_errno;
|
||||
}
|
||||
|
||||
return ¤t_process->error_no;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
/// MentOS, The Mentoring Operating system project
|
||||
/// @file panic.c
|
||||
/// @brief Functions used to manage kernel panic.
|
||||
/// @copyright (c) 2019 This file is distributed under the MIT License.
|
||||
/// @copyright (c) 2014-2021 This file is distributed under the MIT License.
|
||||
/// See LICENSE.md for details.
|
||||
|
||||
#include "panic.h"
|
||||
#include "elf.h"
|
||||
#include "stdio.h"
|
||||
#include "kernel.h"
|
||||
#include "debug.h"
|
||||
|
||||
void kernel_panic(const char *msg)
|
||||
{
|
||||
dbg_print("\nPANIC:\n%s\n\nWelcome to Kernel Debugging Land...\n\n", msg);
|
||||
dbg_print("\n");
|
||||
for (;;);
|
||||
pr_emerg("\nPANIC:\n%s\n\nWelcome to Kernel Debugging Land...\n\n", msg);
|
||||
pr_emerg("\n");
|
||||
asm("cli"); // Disable interrupts
|
||||
for (;;) asm("hlt"); // Decrease power consumption with hlt
|
||||
}
|
||||
|
||||
+11
-12
@@ -1,7 +1,7 @@
|
||||
/// MentOS, The Mentoring Operating system project
|
||||
/// @file printk.c
|
||||
/// @brief
|
||||
/// @copyright (c) 2019 This file is distributed under the MIT License.
|
||||
/// @brief Functions for managing the kernel messages.
|
||||
/// @copyright (c) 2014-2021 This file is distributed under the MIT License.
|
||||
/// See LICENSE.md for details.
|
||||
|
||||
#include "printk.h"
|
||||
@@ -9,15 +9,14 @@
|
||||
#include "stdio.h"
|
||||
#include "video.h"
|
||||
|
||||
void printk(const char *format, ...)
|
||||
int sys_syslog(const char *format, ...)
|
||||
{
|
||||
char buffer[4096];
|
||||
va_list ap;
|
||||
// Start variabile argument's list.
|
||||
va_start(ap, format);
|
||||
int len = vsprintf(buffer, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
for (size_t i = 0; (i < len); ++i)
|
||||
video_putc(buffer[i]);
|
||||
char buffer[4096];
|
||||
va_list ap;
|
||||
// Start variabile argument's list.
|
||||
va_start(ap, format);
|
||||
int len = vsprintf(buffer, format, ap);
|
||||
va_end(ap);
|
||||
video_puts(buffer);
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,798 @@
|
||||
/// MentOS, The Mentoring Operating system project
|
||||
/// @file signal.c
|
||||
/// @brief Signals definition.
|
||||
/// @copyright (c) 2014-2021 This file is distributed under the MIT License.
|
||||
/// See LICENSE.md for details.
|
||||
|
||||
/// Change the header.
|
||||
#define __DEBUG_HEADER__ "[SIGNAL]"
|
||||
|
||||
#include "signal.h"
|
||||
#include "wait.h"
|
||||
#include "scheduler.h"
|
||||
#include "process.h"
|
||||
#include "errno.h"
|
||||
#include "assert.h"
|
||||
#include "debug.h"
|
||||
#include "string.h"
|
||||
#include "irqflags.h"
|
||||
|
||||
/// SLAB caches for signal bits.
|
||||
static kmem_cache_t *sigqueue_cachep;
|
||||
|
||||
/// Contains all stopped process waiting for a continue signal
|
||||
static struct wait_queue_head_t stopped_queue;
|
||||
|
||||
static const char *sys_siglist[] = {
|
||||
"HUP",
|
||||
"INT",
|
||||
"QUIT",
|
||||
"ILL",
|
||||
"TRAP",
|
||||
"ABRT",
|
||||
"EMT",
|
||||
"FPE",
|
||||
"KILL",
|
||||
"BUS",
|
||||
"SEGV",
|
||||
"SYS",
|
||||
"PIPE",
|
||||
"ALRM",
|
||||
"TERM",
|
||||
"USR1",
|
||||
"USR2",
|
||||
"CHLD",
|
||||
"PWR",
|
||||
"WINCH",
|
||||
"URG",
|
||||
"POLL",
|
||||
"STOP",
|
||||
"TSTP",
|
||||
"CONT",
|
||||
"TTIN",
|
||||
"TTOU",
|
||||
"VTALRM",
|
||||
"PROF",
|
||||
"XCPU",
|
||||
"XFSZ",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static inline void __copy_siginfo(siginfo_t *to, const siginfo_t *from)
|
||||
{
|
||||
memcpy(to, from, sizeof(*to));
|
||||
}
|
||||
|
||||
static inline void __clear_siginfo(siginfo_t *info)
|
||||
{
|
||||
memset(info, 0, sizeof(*info));
|
||||
}
|
||||
|
||||
static inline void __lock_task_sighand(struct task_struct *t)
|
||||
{
|
||||
assert(t && "Null task struct.");
|
||||
spinlock_lock(&t->sighand.siglock);
|
||||
}
|
||||
|
||||
static inline void __unlock_task_sighand(struct task_struct *t)
|
||||
{
|
||||
assert(t && "Null task struct.");
|
||||
spinlock_unlock(&t->sighand.siglock);
|
||||
}
|
||||
|
||||
static sighandler_t __get_handler(struct task_struct *t, int sig)
|
||||
{
|
||||
assert(t && "Null task struct.");
|
||||
return t->sighand.action[sig - 1].sa_handler;
|
||||
}
|
||||
|
||||
static int __sig_is_ignored(struct task_struct *t, int sig)
|
||||
{
|
||||
// Blocked signals are never ignored, since the
|
||||
// signal handler may change by the time it is
|
||||
// unblocked.
|
||||
if (sigismember(&t->blocked, sig) || sigismember(&t->real_blocked, sig))
|
||||
return 0;
|
||||
// Get the signal handler.
|
||||
sighandler_t handler = __get_handler(t, sig);
|
||||
// Check the type of the handler.
|
||||
return (handler == SIG_IGN) && (sig != SIGCHLD);
|
||||
// TODO: do_signal() specifically checks if the handler is IGN and the signal
|
||||
// is SIGCHLD, in that case it forces a wait for the parent, that's why
|
||||
// here I'm also accepting as not-ignored a SIG_IGN which is a SIGCHLD.
|
||||
}
|
||||
|
||||
/// @brief Allocate a new signal queue record.
|
||||
/// @param t The task to which the signal belongs.
|
||||
/// @param sig The signal to set.
|
||||
/// @param flags Flags identifying from where we are going to take the memory.
|
||||
static sigqueue_t *__sigqueue_alloc(struct task_struct *t, int sig, gfp_t flags)
|
||||
{
|
||||
sigqueue_t *q = NULL;
|
||||
if ((q = kmem_cache_alloc(sigqueue_cachep, flags)) == NULL)
|
||||
return NULL;
|
||||
// Initiliaze the values.
|
||||
q->flags = 0;
|
||||
list_head_init(&q->list);
|
||||
return q;
|
||||
}
|
||||
|
||||
static void __sigqueue_free(sigqueue_t *q)
|
||||
{
|
||||
if (q)
|
||||
kmem_cache_free(q);
|
||||
}
|
||||
|
||||
/// @brief
|
||||
/// @param sig Signal to be sent.
|
||||
/// @param info The signal info
|
||||
/// @param t The process to which we send the signal.
|
||||
/// @return
|
||||
static int __send_signal(int sig, siginfo_t *info, struct task_struct *t)
|
||||
{
|
||||
// Lock the signal handling for the given task.
|
||||
__lock_task_sighand(t);
|
||||
pr_debug("Trying to add signal (%2d)`%s` to task (%2d)`%s`, currently pending `%d, %d`.\n",
|
||||
sig, strsignal(sig), t->pid, t->name, t->pending.signal.sig[0], t->pending.signal.sig[1]);
|
||||
// Check if the signal is ignored.
|
||||
if (__sig_is_ignored(t, sig)) {
|
||||
pr_debug("Trying to send signal (%2d)`%s` to task (%2d)`%s`: ignored.\n",
|
||||
sig, strsignal(sig), t->pid, t->name);
|
||||
__unlock_task_sighand(t);
|
||||
return 0;
|
||||
}
|
||||
// Check if the process is in an invalid status.
|
||||
if ((t->state == EXIT_ZOMBIE) || (t->state == EXIT_DEAD)) {
|
||||
pr_debug("Trying to send signal (%2d)`%s` to task (%2d)`%s`: zombie or dead.\n",
|
||||
sig, strsignal(sig), t->pid, t->name);
|
||||
__unlock_task_sighand(t);
|
||||
return -EINVAL;
|
||||
}
|
||||
sigqueue_t *q = __sigqueue_alloc(t, sig, GFP_KERNEL);
|
||||
if (q == NULL) {
|
||||
__unlock_task_sighand(t);
|
||||
return -EAGAIN;
|
||||
}
|
||||
list_head_add_tail(&q->list, &t->pending.list);
|
||||
if (info != SEND_SIG_NOINFO)
|
||||
memcpy(&q->info, info, sizeof(siginfo_t));
|
||||
// Set that there is a signal pending.
|
||||
sigaddset(&t->pending.signal, sig);
|
||||
pr_debug("Added pending signal (%2d)`%s` to task (%2d)`%s`, pending `%d, %d`.\n",
|
||||
sig, strsignal(sig), t->pid, t->name, t->pending.signal.sig[0], t->pending.signal.sig[1]);
|
||||
__unlock_task_sighand(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int __next_signal(sigpending_t *pending, sigset_t *mask)
|
||||
{
|
||||
pr_debug("__next_signal(%p, %p)\n", pending, mask);
|
||||
assert(pending && "Null `pending` structure.");
|
||||
assert(mask && "Null `mask` structure.");
|
||||
unsigned long x;
|
||||
if ((x = bitmask_clear(pending->signal.sig[0], mask->sig[0])) != 0)
|
||||
return 1 + find_first_non_zero(x);
|
||||
if ((x = bitmask_clear(pending->signal.sig[1], mask->sig[1])) != 0)
|
||||
return 33 + find_first_non_zero(x);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void __collect_signal(int sig, sigpending_t *list, siginfo_t *info)
|
||||
{
|
||||
pr_debug("__collect_signal(%d, %p, %p)\n", sig, list, info);
|
||||
assert(list && "Null `list` structure.");
|
||||
assert(info && "Null `info` structure.");
|
||||
|
||||
sigqueue_t *queue_entry = NULL;
|
||||
bool_t still_pending = false;
|
||||
// Collect the siginfo appropriate to this signal. Check if
|
||||
// there is another siginfo for the same signal.
|
||||
list_for_each_decl(it, &list->list)
|
||||
{
|
||||
sigqueue_t *q = list_entry(it, sigqueue_t, list);
|
||||
pr_debug("__collect_signal(%d, %p, %p) : Signal in queue : %p(%d : %s).\n", sig, list, info,
|
||||
q, q->info.si_signo, strsignal(q->info.si_signo));
|
||||
if (q->info.si_signo == sig) {
|
||||
// If the entry is already set, this means that there are several handlers
|
||||
// pending for this particular signal.
|
||||
if (queue_entry) {
|
||||
pr_debug("__collect_signal(%d, %p, %p) : Still pending, do not remove from set.\n", sig, list, info);
|
||||
still_pending = true;
|
||||
break;
|
||||
}
|
||||
// Store the entry we encounter.
|
||||
queue_entry = q;
|
||||
}
|
||||
}
|
||||
// If there are no other signals pending of the same type,
|
||||
// remove the signal from the set.
|
||||
if (!still_pending) {
|
||||
sigdelset(&list->signal, sig);
|
||||
pr_debug("__collect_signal(%d, %p, %p) : Remove signal from set: %d.\n", sig, list, info,
|
||||
list->signal.sig[0]);
|
||||
}
|
||||
// If we have found an entry.
|
||||
if (queue_entry) {
|
||||
pr_debug("__collect_signal(%d, %p, %p) : Remove and delete sigqueue entry : %p.\n", sig, list, info, queue_entry);
|
||||
// Remove the entry from the queue.
|
||||
list_head_del(&queue_entry->list);
|
||||
// Copy the details about the entry inside the info structure.
|
||||
__copy_siginfo(info, &queue_entry->info);
|
||||
// Free the memory for the queue entry.
|
||||
__sigqueue_free(queue_entry);
|
||||
} else {
|
||||
pr_debug("__collect_signal(%d, %p, %p) : Cannot find the signal in the queue.\n", sig, list, info);
|
||||
// Ok, it wasn't in the queue, zero out the info.
|
||||
__clear_siginfo(info);
|
||||
// Get the current process.
|
||||
struct task_struct *current = scheduler_get_current_process();
|
||||
assert(current && "There is no running process.");
|
||||
// Initialize the info.
|
||||
info->si_signo = sig;
|
||||
info->si_code = SI_USER;
|
||||
info->si_value.sival_int = 0;
|
||||
info->si_errno = 0;
|
||||
info->si_pid = current->pid;
|
||||
info->si_uid = current->uid;
|
||||
info->si_addr = NULL;
|
||||
info->si_status = 0;
|
||||
info->si_band = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int __dequeue_signal(sigpending_t *pending, sigset_t *mask, siginfo_t *info)
|
||||
{
|
||||
pr_debug("__dequeue_signal(%p, %p, %p)\n", pending, mask, info);
|
||||
// The dequeue_signal( ) always considers the lowest-numbered pending signal.
|
||||
// It updates the data structures to indicate that the signal is no longer
|
||||
// pending and returns its number.
|
||||
int sig = __next_signal(pending, mask);
|
||||
if ((sig > 0) && (sig < NSIG)) {
|
||||
__collect_signal(sig, pending, info);
|
||||
}
|
||||
return sig;
|
||||
}
|
||||
|
||||
static inline int __handle_signal(int signr, siginfo_t *info, sigaction_t *ka, struct pt_regs *regs)
|
||||
{
|
||||
pr_debug("__handle_signal(%d, %p, %p, %p)\n", signr, info, ka, regs);
|
||||
// The do_signal() function is usually only invoked when the CPU is going
|
||||
// to return in User Mode.
|
||||
struct task_struct *current = scheduler_get_current_process();
|
||||
assert(current && "There is no running process.");
|
||||
// Skip the `init` process, always.
|
||||
if (current->pid == 1) {
|
||||
errno = ESRCH;
|
||||
return 0;
|
||||
}
|
||||
// Save the previous signal mask.
|
||||
memcpy(¤t->saved_sigmask, ¤t->blocked, sizeof(sigset_t));
|
||||
|
||||
// Add the signal to the list of blocked signals.
|
||||
sigaddset(¤t->blocked, signr);
|
||||
|
||||
// Store the registers before setting the ones required by the signal handling.
|
||||
current->thread.signal_regs = *regs;
|
||||
|
||||
// Restore the registers for the process that has set the signal.
|
||||
*regs = current->thread.regs;
|
||||
|
||||
// Set the instruction pointer.
|
||||
regs->eip = (uintptr_t)ka->sa_handler;
|
||||
|
||||
// If the user is also asking for the signal info, push it into the stack.
|
||||
if (bitmask_check(ka->sa_flags, SA_SIGINFO)) {
|
||||
// Move the stack so that we have space for storing the siginfo.
|
||||
regs->useresp -= sizeof(siginfo_t);
|
||||
// Save the pointer where the siginfo is stored.
|
||||
siginfo_t *siginfo_addr = (siginfo_t *)regs->useresp;
|
||||
// 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 on the stack the signal number, first and only argument of the handler.
|
||||
PUSH_ARG(regs->useresp, int, signr);
|
||||
|
||||
// Push on the stack the function required to handle the signal return.
|
||||
PUSH_ARG(regs->useresp, uint32_t, current->sigreturn_eip);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
long sys_sigreturn(struct pt_regs *f)
|
||||
{
|
||||
pr_debug("sys_sigreturn(%p)\n", f);
|
||||
struct task_struct *current = scheduler_get_current_process();
|
||||
assert(current && "There is no running process.");
|
||||
// Restore the registers before the signal handling.
|
||||
*f = current->thread.signal_regs;
|
||||
// Restore the previous signal mask.
|
||||
memcpy(¤t->blocked, ¤t->saved_sigmask, sizeof(sigset_t));
|
||||
// Switch to process page directory
|
||||
paging_switch_directory_va(current->mm->pgd);
|
||||
pr_debug("sys_sigreturn(%p) : done!\n", f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Send signal to parent
|
||||
static int __notify_parent(struct task_struct *current, int signr)
|
||||
{
|
||||
siginfo_t info;
|
||||
info.si_signo = signr;
|
||||
info.si_code = SI_KERNEL;
|
||||
info.si_value.sival_int = 0;
|
||||
info.si_errno = 0;
|
||||
info.si_pid = current->pid;
|
||||
info.si_uid = current->uid;
|
||||
info.si_addr = NULL;
|
||||
info.si_status = 0;
|
||||
info.si_band = 0;
|
||||
return __send_signal(signr, &info, current->parent);
|
||||
}
|
||||
|
||||
// Removes from the pending signal queue q the pending signals corresponding to
|
||||
// the bit mask mask
|
||||
static void __rm_from_queue(sigset_t *mask, sigpending_t *q)
|
||||
{
|
||||
list_head *it, *tmp;
|
||||
list_for_each_safe (it, tmp, &q->list) {
|
||||
struct sigqueue_t *entry = list_entry(it, struct sigqueue_t, list);
|
||||
int sig = entry->info.si_signo;
|
||||
|
||||
if (sigismember(mask, sig)) {
|
||||
list_head_del(it);
|
||||
kfree(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We do not consider group stopping because for now we don't have thread groups
|
||||
static void __do_signal_stop(struct task_struct *current, struct pt_regs *f, int signr)
|
||||
{
|
||||
// The do_signal( ) function also sends a SIGCHLD signal to
|
||||
// the parent process of current, unless the parent has set
|
||||
// the SA_NOCLDSTOP flag of SIGCHLD.
|
||||
if (!(SA_NOCLDSTOP & current->parent->sighand.action[SIGCHLD - 1].sa_flags))
|
||||
if (__notify_parent(current, SIGCHLD) != 0)
|
||||
pr_debug("Failed to notify parent with signal: %d", signr);
|
||||
|
||||
// The state is now TASK_UNINTERRUPTABLE
|
||||
sleep_on(&stopped_queue);
|
||||
|
||||
current->state = TASK_STOPPED;
|
||||
current->exit_code = signr;
|
||||
|
||||
scheduler_run(f);
|
||||
}
|
||||
|
||||
int do_signal(struct pt_regs *f)
|
||||
{
|
||||
// The do_signal() function is usually only invoked when the CPU is going
|
||||
// to return in User Mode.
|
||||
struct task_struct *current = scheduler_get_current_process();
|
||||
if (current == NULL)
|
||||
return 0;
|
||||
|
||||
// First, checks whether the function itself was triggered by an interrupt;
|
||||
// if so, it simply returns. Otherwise, if the function was triggered by an
|
||||
// exception that was raised while the process was running in User Mode,
|
||||
// the function continues executing.
|
||||
if ((f->cs & 3) != 3)
|
||||
return 0;
|
||||
|
||||
// Create a siginfo.
|
||||
siginfo_t info;
|
||||
// The return code of __dequeue_signal( ) is stored in signr.
|
||||
int signr, exit_code;
|
||||
|
||||
// Lock the signal handling for the given task.
|
||||
__lock_task_sighand(current);
|
||||
|
||||
// The heart of the do_signal( ) function consists of a loop that
|
||||
// repeatedly invokes the __dequeue_signal( ) function until no
|
||||
// non-blocked pending signals are left.
|
||||
while (!list_head_empty(¤t->pending.list)) {
|
||||
// Get the signal to deliver.
|
||||
signr = exit_code = __dequeue_signal(¤t->pending, ¤t->blocked, &info);
|
||||
|
||||
// Check the signal that we want to send.
|
||||
if ((signr < 0) || (signr >= NSIG)) {
|
||||
pr_err("Wrong signal number!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
// If its value is 0, it means that all pending signals have been
|
||||
// handled and do_signal( ) can finish.
|
||||
if (signr == 0) {
|
||||
pr_notice("There are no more signals to handle.\n");
|
||||
__unlock_task_sighand(current);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get the associated signal action.
|
||||
sigaction_t *ka = ¤t->sighand.action[signr - 1];
|
||||
|
||||
// The only exception comes when the receiving process is init, in
|
||||
// which case the signal is discarded.
|
||||
if (current->pid == 1)
|
||||
continue;
|
||||
|
||||
// When a delivered signal is explicitly ignored, the do_signal( )
|
||||
// function normally just continues with a new execution of the loop
|
||||
// and therefore considers another pending signal.
|
||||
if (ka->sa_handler == SIG_IGN) {
|
||||
if (signr == SIGCHLD)
|
||||
while (sys_waitpid(-1, NULL, WNOHANG) > 0) {}
|
||||
continue;
|
||||
}
|
||||
|
||||
// When a delivered signal is the default one, do_signal( ) must
|
||||
// perform the default action of the signal.
|
||||
if (ka->sa_handler == SIG_DFL) {
|
||||
// For other processes, since the default action depends on the
|
||||
// type of signal, the function executes a switch statement based
|
||||
// on the value of signr.
|
||||
switch (signr) {
|
||||
// The signals whose default action is "ignore" are easily handled:
|
||||
case SIGCONT:
|
||||
case SIGCHLD:
|
||||
case SIGURG:
|
||||
case SIGWINCH:
|
||||
continue;
|
||||
// The signals whose default action is "stop" may stop the
|
||||
// current process. To do this, do_signal( ) sets the state
|
||||
// of current to TASK_STOPPED and then invokes the schedule( )
|
||||
// function (see Section 11.2.2).
|
||||
// The difference between SIGSTOP and the other signals is:
|
||||
// SIGSTOP always stops the process;
|
||||
// The other signals stop the process only if it is not
|
||||
// in an "orphaned process group."
|
||||
case SIGTSTP:
|
||||
case SIGTTIN:
|
||||
case SIGTTOU:
|
||||
if (is_orphaned_pgrp(current->gid))
|
||||
continue;
|
||||
|
||||
case SIGSTOP:
|
||||
__unlock_task_sighand(current);
|
||||
__do_signal_stop(current, f, signr);
|
||||
__lock_task_sighand(current);
|
||||
|
||||
continue;
|
||||
case SIGQUIT:
|
||||
case SIGILL:
|
||||
case SIGTRAP:
|
||||
|
||||
case SIGABRT:
|
||||
sys_exit(3);
|
||||
|
||||
continue;
|
||||
case SIGFPE:
|
||||
case SIGSEGV:
|
||||
case SIGBUS:
|
||||
case SIGSYS:
|
||||
case SIGXCPU:
|
||||
case SIGXFSZ:
|
||||
#if 0
|
||||
if (do_coredump(signr, f))
|
||||
exit_code |= 0x80;
|
||||
#endif
|
||||
default:
|
||||
#if 0
|
||||
current->flags |= PF_SIGNALED;
|
||||
#endif
|
||||
sys_exit(exit_code);
|
||||
__unlock_task_sighand(current);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (__handle_signal(signr, &info, ka, f) == 1) {
|
||||
__unlock_task_sighand(current);
|
||||
return 1;
|
||||
}
|
||||
pr_emerg("Failed to handle signal.\n");
|
||||
}
|
||||
__unlock_task_sighand(current);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int signals_init()
|
||||
{
|
||||
if ((sigqueue_cachep = KMEM_CREATE(sigqueue_t)) == NULL) {
|
||||
pr_emerg("Failed to allocate cache for signals.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_head_init(&stopped_queue.task_list);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// @brief Checks for some types of signals that might nullify other pending
|
||||
/// signals for the destination thread group
|
||||
/// @param sig Signal number
|
||||
/// @param info siginfo struct of the signal
|
||||
/// @param p Target process of the signal
|
||||
void handle_stop_signal(int sig, siginfo_t *info, struct task_struct *p)
|
||||
{
|
||||
// remove the SIGCONT signal from the shared
|
||||
// pending signal queue p->signal->shared_pending and from the private
|
||||
// queues of all members of the thread group.
|
||||
if (sig == SIGSTOP || sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) {
|
||||
// TODO: shared and thread group
|
||||
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGCONT);
|
||||
|
||||
__rm_from_queue(&mask, &p->pending);
|
||||
}
|
||||
|
||||
// remove any SIGSTOP, SIGTSTP, SIGTTIN, and SIGTTOU signal from the shared pending signal queue p->signal->shared_pending;
|
||||
// then, removes the same signals from the private pending signal queues of the processes belonging to the thread
|
||||
// group, and awakens them
|
||||
if (sig == SIGCONT) {
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
|
||||
sigaddset(&mask, SIGSTOP);
|
||||
sigaddset(&mask, SIGTSTP);
|
||||
sigaddset(&mask, SIGTTIN);
|
||||
sigaddset(&mask, SIGTTOU);
|
||||
|
||||
__rm_from_queue(&mask, &p->pending);
|
||||
|
||||
struct list_head *it, *tmp;
|
||||
list_for_each_safe (it, tmp, &stopped_queue.task_list) {
|
||||
struct wait_queue_entry_t *entry = list_entry(it, struct wait_queue_entry_t, task_list);
|
||||
|
||||
// Select only the waiting entry for the timer task pid
|
||||
task_struct *task = entry->task;
|
||||
if (task->pid == p->pid) {
|
||||
// Executed entry's wakeup test function
|
||||
int res = entry->func(entry, 0, 0);
|
||||
if (res == 1) {
|
||||
// Removes entry from list and memory
|
||||
remove_wait_queue(&stopped_queue, entry);
|
||||
kfree(entry);
|
||||
|
||||
pr_debug("Process (pid: %d) restored from stop\n", p->pid);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Send siginfo to target process
|
||||
/// @param sig Signal number
|
||||
/// @param info siginfo struct of the signal to be sent
|
||||
/// @param p Target process where the signal will be sent
|
||||
/// @return Returns 0 if there is no error, otherwise returns an error code
|
||||
int __send_sig_info(int sig, siginfo_t *info, struct task_struct *p)
|
||||
{
|
||||
if (sig < 0 || sig > NSIG)
|
||||
return -EINVAL;
|
||||
|
||||
// If the signal is being sent by a User Mode process,
|
||||
// it checks whether the operation is allowed.
|
||||
if (info->si_code == SI_USER) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
// If the sig parameter has the value 0,
|
||||
// it returns immediately without generating any signal
|
||||
if (!sig)
|
||||
return 0;
|
||||
|
||||
__lock_task_sighand(p);
|
||||
|
||||
// Checks for some types of signals that might nullify other pending
|
||||
// signals for the destination thread group
|
||||
handle_stop_signal(sig, info, p);
|
||||
|
||||
#if 0
|
||||
// Checks whether the signal is non-real-time and another occurrence of the same
|
||||
// signal is already pending in the shared pending signal queue of the thread group
|
||||
if (sig < 32 && sigismember(&p->signal->shared_pending.signal,sig))
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
__unlock_task_sighand(p);
|
||||
__send_signal(sig, info, p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_kill(pid_t pid, int sig)
|
||||
{
|
||||
pr_debug("sys_kill(%d, %d)\n", pid, sig);
|
||||
struct task_struct *current = scheduler_get_running_process(pid);
|
||||
// Check the task associated with the pid.
|
||||
if (!current)
|
||||
return -ESRCH;
|
||||
// Check the signal that we want to send.
|
||||
if ((sig < 0) || (sig >= NSIG))
|
||||
return -EINVAL;
|
||||
siginfo_t info;
|
||||
info.si_signo = sig;
|
||||
info.si_code = SI_USER;
|
||||
info.si_value.sival_int = 0;
|
||||
info.si_errno = 0;
|
||||
info.si_pid = current->pid;
|
||||
info.si_uid = current->uid;
|
||||
info.si_addr = NULL;
|
||||
info.si_status = 0;
|
||||
info.si_band = 0;
|
||||
return __send_sig_info(sig, &info, current);
|
||||
}
|
||||
|
||||
sighandler_t sys_signal(int signum, sighandler_t handler)
|
||||
{
|
||||
pr_notice("sys_signal(%d, %p)\n", signum, handler);
|
||||
// Check the signal that we want to send.
|
||||
if ((signum < 0) || (signum >= NSIG)) {
|
||||
pr_err("sys_signal(%d, %p): Wrong signal number!\n", signum, handler);
|
||||
return SIG_ERR;
|
||||
}
|
||||
// The do_signal() function is usually only invoked when the CPU is going
|
||||
// to return in User Mode.
|
||||
struct task_struct *current = scheduler_get_current_process();
|
||||
assert(current && "There is no running process.");
|
||||
// Skip the `init` process, always.
|
||||
if (current->pid == 1) {
|
||||
pr_err("sys_signal(%d, %p): Cannot signal number!\n", signum, handler);
|
||||
return SIG_ERR;
|
||||
}
|
||||
// Create a new signal action.
|
||||
sigaction_t new_sigaction;
|
||||
// Set the handler.
|
||||
new_sigaction.sa_handler = handler;
|
||||
// Set the handler.
|
||||
new_sigaction.sa_flags = SA_RESETHAND | SA_NODEFER;
|
||||
// Reset the set for the signal action.
|
||||
sigemptyset(&new_sigaction.sa_mask);
|
||||
// Lock the signal handling for the given task.
|
||||
__lock_task_sighand(current);
|
||||
// Get the old sigaction.
|
||||
sigaction_t *old_sigaction = ¤t->sighand.action[signum - 1];
|
||||
pr_err("sys_signal(%d, %p): Signal action ptr %p\n", signum, handler, old_sigaction);
|
||||
pr_err("sys_signal(%d, %p): Old signal handler %p\n", signum, handler, old_sigaction->sa_handler);
|
||||
// Get the old handler (to return).
|
||||
sighandler_t old_handler = current->sighand.action[signum - 1].sa_handler;
|
||||
// Set the new action.
|
||||
memcpy(old_sigaction, &new_sigaction, sizeof(sigaction_t));
|
||||
// Unlock the signal handling for the given task.
|
||||
__unlock_task_sighand(current);
|
||||
// Return the old sighandler.
|
||||
return old_handler;
|
||||
}
|
||||
|
||||
int sys_sigaction(int signum, const sigaction_t *act, sigaction_t *oldact)
|
||||
{
|
||||
pr_debug("sys_sigaction(%d, %p, %p)\n", signum, act, oldact);
|
||||
// Check the signal that we want to send.
|
||||
if ((signum < 0) || (signum >= NSIG)) {
|
||||
pr_debug("sys_sigaction(%d, %p, %p): Wrong signal number!\n", signum, act, oldact);
|
||||
return -EINVAL;
|
||||
}
|
||||
// The do_signal() function is usually only invoked when the CPU is going
|
||||
// to return in User Mode.
|
||||
struct task_struct *current = scheduler_get_current_process();
|
||||
assert(current && "There is no running process.");
|
||||
// Skip the `init` process, always.
|
||||
if (current->pid == 1) {
|
||||
pr_debug("sys_sigaction(%d, %p, %p): Cannot set signal for init!\n", signum, act, oldact);
|
||||
return -EINVAL;
|
||||
}
|
||||
// Lock the signal handling for the given task.
|
||||
__lock_task_sighand(current);
|
||||
// Get a pointer to the entry in the sighand.action array.
|
||||
sigaction_t *current_sigaction = ¤t->sighand.action[signum - 1];
|
||||
pr_debug("sys_sigaction(%d, %p, %p): : Signal old action ptr %p\n", signum, act, oldact, current_sigaction);
|
||||
// If requested, get the old sigaction.
|
||||
if (oldact) {
|
||||
memcpy(oldact, current_sigaction, sizeof(sigaction_t));
|
||||
}
|
||||
// Set the new action.
|
||||
memcpy(current_sigaction, act, sizeof(sigaction_t));
|
||||
// Unlock the signal handling for the given task.
|
||||
__unlock_task_sighand(current);
|
||||
// Return the old sighandler.
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
|
||||
{
|
||||
pr_notice("sys_sigprocmask(%d, %p, %p)\n", how, set, oldset);
|
||||
if (!set && !oldset) {
|
||||
return -EFAULT;
|
||||
}
|
||||
if ((how < SIG_BLOCK) || (how > SIG_SETMASK)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
// The do_signal() function is usually only invoked when the CPU is going
|
||||
// to return in User Mode.
|
||||
struct task_struct *current = scheduler_get_current_process();
|
||||
assert(current && "There is no running process.");
|
||||
// Skip the `init` process, always.
|
||||
if (current->pid == 1) {
|
||||
pr_notice("sys_sigprocmask(%d, %p, %p): Cannot set signal for init!\n", how, set, oldset);
|
||||
return -EINVAL;
|
||||
}
|
||||
// If `oldset` is not, return the old set.
|
||||
if (oldset) {
|
||||
oldset->sig[0] = current->blocked.sig[0];
|
||||
oldset->sig[1] = current->blocked.sig[1];
|
||||
}
|
||||
// Set the new signal mask.
|
||||
if (set) {
|
||||
if (how == SIG_BLOCK) {
|
||||
// The set of blocked signals is the union of the current set
|
||||
// and the set argument.
|
||||
current->blocked.sig[0] |= set->sig[0];
|
||||
current->blocked.sig[1] |= set->sig[1];
|
||||
} else if (how == SIG_UNBLOCK) {
|
||||
// The signals in set are removed from the current set of
|
||||
// blocked signals. It is permissible to attempt to unblock
|
||||
// a signal which is not blocked.
|
||||
current->blocked.sig[0] &= ~(set->sig[0]);
|
||||
current->blocked.sig[1] &= ~(set->sig[1]);
|
||||
} else if (how == SIG_SETMASK) {
|
||||
// The set of blocked signals is set to the argument set.
|
||||
current->blocked.sig[0] = set->sig[0];
|
||||
current->blocked.sig[1] = set->sig[1];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *strsignal(int sig)
|
||||
{
|
||||
if ((sig >= SIGHUP) && (sig < NSIG))
|
||||
return sys_siglist[sig - 1];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int sigemptyset(sigset_t *set)
|
||||
{
|
||||
if (set) {
|
||||
set->sig[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sigfillset(sigset_t *set)
|
||||
{
|
||||
if (set) {
|
||||
set->sig[0] = ~0UL;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sigaddset(sigset_t *set, int signum)
|
||||
{
|
||||
if (set && ((signum))) {
|
||||
bit_set_assign(set->sig[(signum - 1) / 32], ((signum - 1) % 32));
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sigdelset(sigset_t *set, int signum)
|
||||
{
|
||||
if (set) {
|
||||
bit_clear_assign(set->sig[(signum - 1) / 32], ((signum - 1) % 32));
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sigismember(sigset_t *set, int signum)
|
||||
{
|
||||
if (set)
|
||||
return bit_check(set->sig[(signum - 1) / 32], (signum - 1) % 32);
|
||||
return -1;
|
||||
}
|
||||
+120
-67
@@ -1,100 +1,153 @@
|
||||
/// MentOS, The Mentoring Operating system project
|
||||
/// @file syscall.c
|
||||
/// @brief System Call management functions.
|
||||
/// @copyright (c) 2019 This file is distributed under the MIT License.
|
||||
/// @copyright (c) 2014-2021 This file is distributed under the MIT License.
|
||||
/// See LICENSE.md for details.
|
||||
|
||||
#include "fpu.h"
|
||||
#include "kheap.h"
|
||||
#include "syscall.h"
|
||||
#include "shm.h"
|
||||
#include "isr.h"
|
||||
#include "errno.h"
|
||||
#include "video.h"
|
||||
#include "fcntl.h"
|
||||
#include "kernel.h"
|
||||
#include "unistd.h"
|
||||
#include "process.h"
|
||||
#include "process.h"
|
||||
#include "irqflags.h"
|
||||
#include "scheduler.h"
|
||||
#include "utsname.h"
|
||||
#include "ioctl.h"
|
||||
#include "timer.h"
|
||||
|
||||
/// @brief The signature of a function call.
|
||||
#include "ipc/msg.h"
|
||||
#include "ipc/sem.h"
|
||||
#include "ipc/shm.h"
|
||||
|
||||
/// The signature of a function call.
|
||||
typedef int (*SystemCall)();
|
||||
|
||||
/// @brief The signature used to call the system call.
|
||||
typedef uint32_t (*SystemCallFun)(uint32_t, ...);
|
||||
|
||||
/// @brief The list of function call.
|
||||
/// The list of function call.
|
||||
SystemCall sys_call_table[SYSCALL_NUMBER];
|
||||
|
||||
// Linux provides a "not implemented" system call, sys_ni_syscall(), which does
|
||||
// nothing except return ENOSYS, the error corresponding to an invalid
|
||||
// system call. This function is used to "plug the hole" in the rare event that
|
||||
// a syscall is removed or otherwise made unavailable.
|
||||
int sys_ni_syscall()
|
||||
/// Last interupt stack frame
|
||||
static pt_regs *current_interrupt_stack_frame;
|
||||
|
||||
/// @brief A Not Implemented (NI) system-call.
|
||||
/// @return Always returns -ENOSYS.
|
||||
/// @details
|
||||
/// Linux provides a "not implemented" system call, sys_ni_syscall(), which does
|
||||
/// nothing except return ENOSYS, the error corresponding to an invalid
|
||||
/// system call. This function is used to "plug the hole" in the rare event that
|
||||
/// a syscall is removed or otherwise made unavailable.
|
||||
static inline int sys_ni_syscall()
|
||||
{
|
||||
return ENOSYS;
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
void syscall_init()
|
||||
{
|
||||
// Initialize the list of system calls.
|
||||
for (uint32_t it = 0; it < SYSCALL_NUMBER; ++it) {
|
||||
sys_call_table[it] = sys_ni_syscall;
|
||||
}
|
||||
// Initialize the list of system calls.
|
||||
for (uint32_t it = 0; it < SYSCALL_NUMBER; ++it) {
|
||||
sys_call_table[it] = sys_ni_syscall;
|
||||
}
|
||||
|
||||
sys_call_table[__NR_exit] = (SystemCall)sys_exit;
|
||||
sys_call_table[__NR_read] = (SystemCall)sys_read;
|
||||
sys_call_table[__NR_write] = (SystemCall)sys_write;
|
||||
sys_call_table[__NR_open] = (SystemCall)sys_open;
|
||||
sys_call_table[__NR_close] = (SystemCall)sys_close;
|
||||
sys_call_table[__NR_stat] = (SystemCall)sys_stat;
|
||||
sys_call_table[__NR_mkdir] = (SystemCall)sys_mkdir;
|
||||
sys_call_table[__NR_readdir] = (SystemCall)sys_readdir;
|
||||
sys_call_table[__NR_getpid] = (SystemCall)sys_getpid;
|
||||
sys_call_table[__NR_getppid] = (SystemCall)sys_getppid;
|
||||
sys_call_table[__NR_vfork] = (SystemCall)sys_vfork;
|
||||
sys_call_table[__NR_execve] = (SystemCall)sys_execve;
|
||||
sys_call_table[__NR_nice] = (SystemCall)sys_nice;
|
||||
sys_call_table[__NR_reboot] = (SystemCall)sys_reboot;
|
||||
sys_call_table[__NR_waitpid] = (SystemCall)sys_waitpid;
|
||||
sys_call_table[__NR_chdir] = (SystemCall)sys_chdir;
|
||||
sys_call_table[__NR_getcwd] = (SystemCall)sys_getcwd;
|
||||
sys_call_table[__NR_brk] = (SystemCall)umalloc; // TODO: sys_brk
|
||||
sys_call_table[__NR_free] = (SystemCall)ufree; // TODO: sys_brk
|
||||
sys_call_table[__NR_exit] = (SystemCall)sys_exit;
|
||||
sys_call_table[__NR_read] = (SystemCall)sys_read;
|
||||
sys_call_table[__NR_write] = (SystemCall)sys_write;
|
||||
sys_call_table[__NR_open] = (SystemCall)sys_open;
|
||||
sys_call_table[__NR_close] = (SystemCall)sys_close;
|
||||
sys_call_table[__NR_stat] = (SystemCall)sys_stat;
|
||||
sys_call_table[__NR_fstat] = (SystemCall)sys_fstat;
|
||||
sys_call_table[__NR_mkdir] = (SystemCall)sys_mkdir;
|
||||
sys_call_table[__NR_rmdir] = (SystemCall)sys_rmdir;
|
||||
sys_call_table[__NR_unlink] = (SystemCall)sys_unlink;
|
||||
sys_call_table[__NR_getdents] = (SystemCall)sys_getdents;
|
||||
sys_call_table[__NR_lseek] = (SystemCall)sys_lseek;
|
||||
sys_call_table[__NR_getpid] = (SystemCall)sys_getpid;
|
||||
sys_call_table[__NR_getsid] = (SystemCall)sys_getsid;
|
||||
sys_call_table[__NR_setsid] = (SystemCall)sys_setsid;
|
||||
sys_call_table[__NR_getgid] =(SystemCall)sys_getgid;
|
||||
sys_call_table[__NR_setgid] =(SystemCall)sys_setgid;
|
||||
sys_call_table[__NR_getppid] = (SystemCall)sys_getppid;
|
||||
sys_call_table[__NR_sigaction] = (SystemCall)sys_sigaction;
|
||||
sys_call_table[__NR_fork] = (SystemCall)sys_fork;
|
||||
sys_call_table[__NR_execve] = (SystemCall)sys_execve;
|
||||
sys_call_table[__NR_nice] = (SystemCall)sys_nice;
|
||||
sys_call_table[__NR_kill] = (SystemCall)sys_kill;
|
||||
sys_call_table[__NR_reboot] = (SystemCall)sys_reboot;
|
||||
sys_call_table[__NR_uname] = (SystemCall)sys_uname;
|
||||
sys_call_table[__NR_sigreturn] = (SystemCall)sys_sigreturn;
|
||||
sys_call_table[__NR_waitpid] = (SystemCall)sys_waitpid;
|
||||
sys_call_table[__NR_chdir] = (SystemCall)sys_chdir;
|
||||
sys_call_table[__NR_fchdir] = (SystemCall)sys_fchdir;
|
||||
sys_call_table[__NR_time] = (SystemCall)sys_time;
|
||||
sys_call_table[__NR_sigprocmask] = (SystemCall)sys_sigprocmask;
|
||||
sys_call_table[__NR_brk] = (SystemCall)sys_brk;
|
||||
sys_call_table[__NR_signal] = (SystemCall)sys_signal;
|
||||
sys_call_table[__NR_ioctl] = (SystemCall)sys_ioctl;
|
||||
sys_call_table[__NR_sched_setparam] = (SystemCall)sys_sched_setparam;
|
||||
sys_call_table[__NR_sched_getparam] = (SystemCall)sys_sched_getparam;
|
||||
sys_call_table[__NR_nanosleep] = (SystemCall)sys_nanosleep;
|
||||
sys_call_table[__NR_getcwd] = (SystemCall)sys_getcwd;
|
||||
sys_call_table[__NR_waitperiod] = (SystemCall)sys_waitperiod;
|
||||
sys_call_table[__NR_msgctl] = (SystemCall)sys_msgctl;
|
||||
sys_call_table[__NR_msgget] = (SystemCall)sys_msgget;
|
||||
sys_call_table[__NR_msgrcv] = (SystemCall)sys_msgrcv;
|
||||
sys_call_table[__NR_msgsnd] = (SystemCall)sys_msgsnd;
|
||||
sys_call_table[__NR_semctl] = (SystemCall)sys_semctl;
|
||||
sys_call_table[__NR_semget] = (SystemCall)sys_semget;
|
||||
sys_call_table[__NR_semop] = (SystemCall)sys_semop;
|
||||
sys_call_table[__NR_shmat] = (SystemCall)sys_shmat;
|
||||
sys_call_table[__NR_shmctl] = (SystemCall)sys_shmctl;
|
||||
sys_call_table[__NR_shmdt] = (SystemCall)sys_shmdt;
|
||||
sys_call_table[__NR_shmget] = (SystemCall)sys_shmget;
|
||||
sys_call_table[__NR_alarm] = (SystemCall)sys_alarm;
|
||||
sys_call_table[__NR_setitimer] = (SystemCall)sys_setitimer;
|
||||
sys_call_table[__NR_getitimer] = (SystemCall)sys_getitimer;
|
||||
|
||||
isr_install_handler(SYSTEM_CALL, &syscall_handler, "syscall_handler");
|
||||
isr_install_handler(SYSTEM_CALL, &syscall_handler, "syscall_handler");
|
||||
}
|
||||
|
||||
pt_regs *get_current_interrupt_stack_frame()
|
||||
{
|
||||
return current_interrupt_stack_frame;
|
||||
}
|
||||
|
||||
void syscall_handler(pt_regs *f)
|
||||
{
|
||||
// print_intrframe(f);
|
||||
// Saves current interrupt stack frame
|
||||
current_interrupt_stack_frame = f;
|
||||
|
||||
// The index of the requested system call.
|
||||
uint32_t sc_index = f->eax;
|
||||
// dbg_print_regs(f);
|
||||
// Save current process fpu state.
|
||||
switch_fpu();
|
||||
|
||||
// The result of the system call.
|
||||
int ret;
|
||||
if (sc_index >= SYSCALL_NUMBER) {
|
||||
ret = ENOSYS;
|
||||
} else {
|
||||
uintptr_t ptr = (uintptr_t)sys_call_table[sc_index];
|
||||
// The index of the requested system call.
|
||||
uint32_t sc_index = f->eax;
|
||||
|
||||
SystemCallFun func = (SystemCallFun)ptr;
|
||||
// The result of the system call.
|
||||
int ret;
|
||||
if (sc_index >= SYSCALL_NUMBER) {
|
||||
ret = ENOSYS;
|
||||
} else {
|
||||
uintptr_t ptr = (uintptr_t)sys_call_table[sc_index];
|
||||
|
||||
uint32_t arg0 = f->ebx;
|
||||
uint32_t arg1 = f->ecx;
|
||||
uint32_t arg2 = f->edx;
|
||||
uint32_t arg3 = f->esi;
|
||||
uint32_t arg4 = f->edi;
|
||||
if ((sc_index == __NR_vfork) || (sc_index == __NR_clone)) {
|
||||
arg0 = (uintptr_t)f;
|
||||
} else if (sc_index == __NR_execve) {
|
||||
arg0 = (uintptr_t)f;
|
||||
}
|
||||
ret = func(arg0, arg1, arg2, arg3, arg4);
|
||||
}
|
||||
f->eax = ret;
|
||||
SystemCall func = (SystemCall)ptr;
|
||||
|
||||
// Schedule next process.
|
||||
kernel_schedule(f);
|
||||
uint32_t arg0 = f->ebx;
|
||||
uint32_t arg1 = f->ecx;
|
||||
uint32_t arg2 = f->edx;
|
||||
uint32_t arg3 = f->esi;
|
||||
uint32_t arg4 = f->edi;
|
||||
if ((sc_index == __NR_fork) ||
|
||||
(sc_index == __NR_clone) ||
|
||||
(sc_index == __NR_execve) ||
|
||||
(sc_index == __NR_sigreturn)) {
|
||||
arg0 = (uintptr_t)f;
|
||||
}
|
||||
ret = func(arg0, arg1, arg2, arg3, arg4);
|
||||
}
|
||||
f->eax = ret;
|
||||
|
||||
// Schedule next process.
|
||||
scheduler_run(f);
|
||||
// Restore fpu state.
|
||||
unswitch_fpu();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user