Handout
This commit is contained in:
41
kernel/syscall/handler.asm
Normal file
41
kernel/syscall/handler.asm
Normal file
@@ -0,0 +1,41 @@
|
||||
; Generic high-level syscall handler
|
||||
[EXTERN syscall_handler]
|
||||
|
||||
; Low-level interrupt based system call entry function
|
||||
[GLOBAL syscall_entry]
|
||||
|
||||
[SECTION .text]
|
||||
|
||||
; The SystemV ABI for x64 uses the register `rdi`, `rsi`, `rdx`, `rcx`, `r8` and
|
||||
; `r9` to pass the first six parameters of a function. Since every syscall can
|
||||
; have a maximum of 5 parameters, these register will just be forwarded (without
|
||||
; requiring any additional operation), having the syscall number stored in `rdi`.
|
||||
; The return value will be stored in `rax`.
|
||||
ALIGN 8
|
||||
syscall_entry:
|
||||
; Interrupt Context Pointer (7th Parameter)
|
||||
push rsp
|
||||
|
||||
; Clear direction flag for string operations
|
||||
cld
|
||||
|
||||
; Call the high-level (C++) system call handler
|
||||
call syscall_handler
|
||||
|
||||
; Optional: Prevent kernel information leakage
|
||||
; by zeroing scratch registers
|
||||
mov rdi, 0
|
||||
mov rsi, 0
|
||||
mov rdx, 0
|
||||
mov rcx, 0
|
||||
mov r8, 0
|
||||
mov r9, 0
|
||||
mov r10, 0
|
||||
mov r11, 0
|
||||
|
||||
; Drop 7th parameter
|
||||
add rsp, 8
|
||||
|
||||
; Return from interrupt entry function
|
||||
iretq
|
||||
|
||||
56
kernel/syscall/handler.cc
Normal file
56
kernel/syscall/handler.cc
Normal file
@@ -0,0 +1,56 @@
|
||||
#include "syscall/handler.h"
|
||||
|
||||
#include "arch/core.h"
|
||||
#include "arch/core_interrupt.h"
|
||||
#include "arch/gdt.h"
|
||||
#include "arch/idt.h"
|
||||
#include "debug/kernelpanic.h"
|
||||
#include "debug/output.h"
|
||||
#include "interrupt/guard.h"
|
||||
#include "syscall/skeleton.h"
|
||||
#include "syscall/stub.h"
|
||||
#include "types.h"
|
||||
|
||||
/*! \brief Interrupt based system call entry function
|
||||
*
|
||||
* Low-level function written in assembly (located in `syscall/handler.asm`),
|
||||
* calls \ref syscall_handler
|
||||
*/
|
||||
extern "C" [[gnu::interrupt]] void syscall_entry(InterruptContext *context);
|
||||
|
||||
namespace Syscall {
|
||||
/*! \brief High level system call handler
|
||||
* called by both low level handler in `syscall/handler.asm`.
|
||||
*
|
||||
* Processes the request by delegating it to the appropriate function identified
|
||||
* by the system call number -- allowing up to five parameters for the system
|
||||
* call.
|
||||
*
|
||||
* \param p1 first parameter
|
||||
* \param p2 second parameter
|
||||
* \param p3 third parameter
|
||||
* \param p4 fourth parameter
|
||||
* \param p5 fifth parameter
|
||||
* \param sysnum identifier for the system call
|
||||
* \param user pointer to the interrupt \ref context (for example to determine
|
||||
* instruction pointer)
|
||||
* \return system call return value
|
||||
*/
|
||||
extern "C" size_t syscall_handler(size_t sysnum, size_t p1, size_t p2,
|
||||
size_t p3, size_t p4, size_t p5,
|
||||
InterruptContext *user) {
|
||||
(void)p1;
|
||||
(void)p2;
|
||||
(void)p3;
|
||||
(void)p4;
|
||||
(void)p5;
|
||||
(void)sysnum;
|
||||
(void)user;
|
||||
return static_cast<size_t>(-1);
|
||||
}
|
||||
|
||||
void init() {
|
||||
// Set interrupt based syscall handler
|
||||
}
|
||||
|
||||
} // namespace Syscall
|
||||
11
kernel/syscall/handler.h
Normal file
11
kernel/syscall/handler.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
/*! \brief User mode system calls
|
||||
*/
|
||||
namespace Syscall {
|
||||
|
||||
/*! \brief Setup Syscalls Interrupt
|
||||
* \param vector valid interrupt vector number (32-255)
|
||||
*/
|
||||
void init();
|
||||
} // namespace Syscall
|
||||
71
kernel/syscall/skeleton.cc
Normal file
71
kernel/syscall/skeleton.cc
Normal file
@@ -0,0 +1,71 @@
|
||||
#include "syscall/skeleton.h"
|
||||
|
||||
#include "debug/kernelpanic.h"
|
||||
#include "debug/output.h"
|
||||
#include "device/textstream.h"
|
||||
#include "interrupt/guard.h"
|
||||
#include "sync/semaphore.h"
|
||||
#include "thread/scheduler.h"
|
||||
|
||||
void *operator new(size_t, void *);
|
||||
|
||||
namespace Syscall {
|
||||
namespace Skeleton {
|
||||
size_t test(Vault &vault, size_t p1, size_t p2, size_t p3, size_t p4,
|
||||
size_t p5) {
|
||||
(void)vault;
|
||||
vault.kout << "test(" << p1 << ", " << p2 << ", " << p3 << ", " << p4
|
||||
<< ", " << p5 << ");" << endl;
|
||||
return 0xdeadbeef;
|
||||
}
|
||||
|
||||
int getpid(Vault &vault) {
|
||||
(void)vault;
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t write(Vault &vault, uint32_t id, const void *buffer, size_t size) {
|
||||
(void)vault;
|
||||
(void)id;
|
||||
(void)buffer;
|
||||
(void)size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t read(Vault &vault, uint32_t id) {
|
||||
(void)vault;
|
||||
(void)id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sleep(Vault &vault, size_t ms) {
|
||||
(void)vault;
|
||||
(void)ms;
|
||||
}
|
||||
|
||||
bool sem_init(Vault &vault, size_t id, uint32_t value) {
|
||||
(void)vault;
|
||||
(void)id;
|
||||
(void)value;
|
||||
return false;
|
||||
}
|
||||
|
||||
void sem_destroy(Vault &vault, size_t id) {
|
||||
(void)vault;
|
||||
(void)id;
|
||||
}
|
||||
|
||||
void sem_signal(Vault &vault, size_t id) {
|
||||
(void)vault;
|
||||
(void)id;
|
||||
}
|
||||
|
||||
void sem_wait(Vault &vault, size_t id) {
|
||||
(void)vault;
|
||||
(void)id;
|
||||
}
|
||||
|
||||
void exit(Vault &vault) { (void)vault; }
|
||||
|
||||
} // namespace Skeleton
|
||||
} // namespace Syscall
|
||||
28
kernel/syscall/skeleton.h
Normal file
28
kernel/syscall/skeleton.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
struct Vault;
|
||||
|
||||
namespace Syscall {
|
||||
|
||||
/*! \brief Implementation of the functionality provided via syscalls
|
||||
*/
|
||||
namespace Skeleton {
|
||||
|
||||
size_t test(Vault &vault, size_t p1, size_t p2, size_t p3, size_t p4,
|
||||
size_t p5);
|
||||
|
||||
int getpid(Vault &vault);
|
||||
size_t write(Vault &vault, uint32_t id, const void *buffer, size_t size);
|
||||
size_t read(Vault &vault, uint32_t id);
|
||||
void sleep(Vault &vault, size_t ms);
|
||||
bool sem_init(Vault &vault, size_t id, uint32_t value);
|
||||
void sem_destroy(Vault &vault, size_t id);
|
||||
void sem_signal(Vault &vault, size_t id);
|
||||
void sem_wait(Vault &vault, size_t id);
|
||||
void exit(Vault &vault);
|
||||
void kill(Vault &vault, size_t pid);
|
||||
|
||||
} // namespace Skeleton
|
||||
} // namespace Syscall
|
||||
10
kernel/syscall/stub.asm
Normal file
10
kernel/syscall/stub.asm
Normal file
@@ -0,0 +1,10 @@
|
||||
[SECTION .text]
|
||||
|
||||
;; sys_call <syscall number> <param1> <param2> <param3> <param4> <param5>
|
||||
;; Globally visible
|
||||
[GLOBAL sys_call]
|
||||
align 8
|
||||
sys_call:
|
||||
; BSB2 1 - Syscall stub
|
||||
|
||||
|
||||
24
kernel/syscall/stub.h
Normal file
24
kernel/syscall/stub.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
namespace Syscall {
|
||||
/*! \brief Syscall IDs
|
||||
* \note the syscall number must correspond to the values in the syscall stub!
|
||||
*/
|
||||
enum class ID : size_t {
|
||||
TEST = 0,
|
||||
};
|
||||
} // namespace Syscall
|
||||
|
||||
/// \brief Syscall stub
|
||||
extern "C" ssize_t sys_call(Syscall::ID id, size_t p1, size_t p2, size_t p3,
|
||||
size_t p4, size_t p5);
|
||||
extern "C" ssize_t sys_safe_call(Syscall::ID id, size_t p1, size_t p2,
|
||||
size_t p3, size_t p4, size_t p5);
|
||||
|
||||
// Interrupt based syscalls
|
||||
[[gnu::always_inline]] static inline ssize_t sys_test(size_t p1, size_t p2,
|
||||
size_t p3, size_t p4,
|
||||
size_t p5) {
|
||||
return sys_call(Syscall::ID::TEST, p1, p2, p3, p4, p5);
|
||||
}
|
||||
Reference in New Issue
Block a user