Implement syscalls, hello world from userspace
This commit is contained in:
@ -57,6 +57,7 @@ SRCFILES += $(call GRABSRC, \
|
||||
std \
|
||||
flanterm/src \
|
||||
flanterm/src/flanterm_backends \
|
||||
syscall \
|
||||
)
|
||||
|
||||
ifeq ($(ARCH),x86_64)
|
||||
|
@ -1,8 +1,9 @@
|
||||
#ifndef COMPILER_ATTR_H_
|
||||
#define COMPILER_ATTR_H_
|
||||
|
||||
#define PACKED __attribute__((packed))
|
||||
#define ALIGNED(x) __attribute__((aligned((x))))
|
||||
#define NORETURN __attribute__((noreturn))
|
||||
#define PACKED __attribute__((packed))
|
||||
#define ALIGNED(x) __attribute__((aligned((x))))
|
||||
#define NORETURN __attribute__((noreturn))
|
||||
#define UNUSED __attribute__((unused))
|
||||
|
||||
#endif // COMPILER_ATTR_H_
|
||||
|
@ -1,13 +1,16 @@
|
||||
#ifndef ERRORS_H_
|
||||
#define ERRORS_H_
|
||||
|
||||
#define E_OK 0
|
||||
#define E_NOMEMORY -1
|
||||
#define E_UNKNOWN_FSTYPE -2
|
||||
#define E_NOENTRY -3
|
||||
#define E_OUTOFBOUNDS -4
|
||||
#define E_UNKNOWN_SDTYPE -5
|
||||
#define E_TODO -6
|
||||
#define E_BADIO -7
|
||||
enum {
|
||||
E_OK = 0,
|
||||
E_NOMEMORY = -1,
|
||||
E_UNKNOWN_FSTYPE = -2,
|
||||
E_NOENTRY = -3,
|
||||
E_OUTOFBOUNDS = -4,
|
||||
E_UNKNOWN_SDTYPE = -5,
|
||||
E_TODO = -6,
|
||||
E_BADIO = -7,
|
||||
E_BADSYSCALL = -8,
|
||||
};
|
||||
|
||||
#endif // ERRORS_H_
|
||||
|
@ -1,14 +1,28 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "cpu.h"
|
||||
#include "vmm.h"
|
||||
#include "pmm/pmm.h"
|
||||
#include "hal/hal.h"
|
||||
#include "bootinfo/bootinfo.h"
|
||||
|
||||
LocalCpuData HAL_CPUS[HAL_CPUS_MAX];
|
||||
|
||||
uint64_t hal_cpu_rdmsr(uint32_t id) {
|
||||
uint32_t lo, hi;
|
||||
asm volatile("rdmsr" : "=m"(lo), "=d"(hi) : "c"(id));
|
||||
asm volatile("rdmsr" : "=a"(lo), "=d"(hi) : "c"(id));
|
||||
return ((uint64_t)lo) | ((uint64_t)hi << 32);
|
||||
}
|
||||
|
||||
uint64_t hal_cpu_wrmsr(uint32_t id, uint64_t val) {
|
||||
uint32_t lo = val & 0xffffffff, hi = (val >> 32) & 0xffffffff;
|
||||
asm volatile("wrmsr" :: "a"(lo), "d"(hi), "c"(id) : "memory");
|
||||
uint32_t lo = val & 0xFFFFFFFF;
|
||||
uint32_t hi = val >> 32;
|
||||
asm volatile("wrmsr" :: "c"(id), "a"(lo), "d"(hi));
|
||||
return val;
|
||||
}
|
||||
|
||||
void hal_cpu_init(uint32_t cpu) {
|
||||
void *addr = pmm_alloc(16) + (16 * HAL_PAGE_SIZE);
|
||||
HAL_CPUS[cpu].syscall_kstack = (uint64_t *)VIRT(addr);
|
||||
HAL_CPUS[cpu].kcr3 = hal_vmm_current_cr3();
|
||||
}
|
||||
|
@ -1,11 +1,36 @@
|
||||
#ifndef HAL_CPU_H_
|
||||
#define HAL_CPU_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "compiler/attr.h"
|
||||
#include "vmm.h"
|
||||
#include "intr.h"
|
||||
|
||||
#define HAL_CPUS_MAX 0xff
|
||||
|
||||
#define HAL_CPU_EFER 0xC0000080
|
||||
|
||||
#define HAL_CPU_STAR 0xC0000081
|
||||
#define HAL_CPU_LSTAR 0xC0000082
|
||||
#define HAL_CPU_CSTAR 0xC0000083
|
||||
#define HAL_CPU_SFMASK 0xC0000084
|
||||
|
||||
#define HAL_CPU_FSBASE 0xC0000100
|
||||
#define HAL_CPU_GSBASE 0xC0000101
|
||||
#define HAL_CPU_KGSBASE 0xC0000102
|
||||
|
||||
typedef struct {
|
||||
uint64_t *syscall_kstack;
|
||||
uint64_t *syscall_ustack;
|
||||
PgTable *kcr3;
|
||||
PgTable *pcr3;
|
||||
IntrStackFrame *frame;
|
||||
} PACKED LocalCpuData;
|
||||
|
||||
uint64_t hal_cpu_rdmsr(uint32_t id);
|
||||
uint64_t hal_cpu_wrmsr(uint32_t id, uint64_t val);
|
||||
void hal_cpu_init(uint32_t cpu);
|
||||
|
||||
extern LocalCpuData HAL_CPUS[HAL_CPUS_MAX];
|
||||
|
||||
#endif // HAL_CPU_H_
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "pic.h"
|
||||
#include "apic.h"
|
||||
#include "pit.h"
|
||||
#include "syscall.h"
|
||||
|
||||
void hal_init(void) {
|
||||
if (!serial_init()) {
|
||||
@ -32,6 +33,7 @@ void hal_init_withmalloc(void) {
|
||||
pit_init();
|
||||
ioapic_setentry(IOAPIC, acpi_remapirq(0x00), INTR_TIMER);
|
||||
hal_intr_disable();
|
||||
hal_syscall_init();
|
||||
}
|
||||
|
||||
void hal_wait(uint32_t ms) {
|
||||
|
@ -133,7 +133,7 @@ void intr_dumpframe(IntrStackFrame *frame) {
|
||||
asm volatile("mov %%cr3, %0" : "=r"(cr3));
|
||||
uint64_t cr4;
|
||||
asm volatile("mov %%cr4, %0" : "=r"(cr4));
|
||||
kprintf_unsafe("rax=%016lx rcx=%016lx rdx=%016lx\n"
|
||||
kprintf("rax=%016lx rcx=%016lx rdx=%016lx\n"
|
||||
"rsi=%016lx rdi=%016lx r8 =%016lx\n"
|
||||
"r9 =%016lx r10=%016lx r11=%016lx\n"
|
||||
"rip=%016lx rfl=%016lx rsp=%016lx\n"
|
||||
@ -150,11 +150,14 @@ void intr_dumpframe(IntrStackFrame *frame) {
|
||||
}
|
||||
|
||||
void intr_handleintr(IntrStackFrame *frame) {
|
||||
if (frame->trapnum >= 0 && frame->trapnum <= 31) {
|
||||
// EXCEPTION
|
||||
kprintf_unsafe("ERROR %s, 0x%lX\n", exceptions[frame->trapnum], frame->errnum);
|
||||
if (frame->trapnum <= 31) {
|
||||
if (frame->trapnum == 14 && frame->errnum & 0x4) {
|
||||
proc_killself();
|
||||
proc_sched((void *)frame);
|
||||
}
|
||||
kprintf("ERROR %s, 0x%lX\n", exceptions[frame->trapnum], frame->errnum);
|
||||
intr_dumpframe(frame);
|
||||
hal_hang();
|
||||
hal_hang();
|
||||
} else if (frame->trapnum >= 32 && frame->trapnum <= 47) {
|
||||
if (frame->trapnum == INTR_TIMER) {
|
||||
io_out8(PIC2_CMD, 0x20);
|
||||
|
@ -17,6 +17,7 @@ typedef struct {
|
||||
uint64_t r10;
|
||||
uint64_t r9;
|
||||
uint64_t r8;
|
||||
uint64_t rbp;
|
||||
uint64_t rdi;
|
||||
uint64_t rsi;
|
||||
uint64_t rdx;
|
||||
|
@ -215,4 +215,3 @@ intr_vec46:
|
||||
intr_vec47:
|
||||
_vecintr_plain_save 47
|
||||
_vecintr_bodygen
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
push %rdx
|
||||
push %rsi
|
||||
push %rdi
|
||||
push %rbp
|
||||
push %r8
|
||||
push %r9
|
||||
push %r10
|
||||
@ -23,6 +24,7 @@
|
||||
pop %r10
|
||||
pop %r9
|
||||
pop %r8
|
||||
pop %rbp
|
||||
pop %rdi
|
||||
pop %rsi
|
||||
pop %rdx
|
||||
|
43
kernel/hal/x86_64/syscall.c
Normal file
43
kernel/hal/x86_64/syscall.c
Normal file
@ -0,0 +1,43 @@
|
||||
#include <stdint.h>
|
||||
#include "syscall.h"
|
||||
#include "cpu.h"
|
||||
#include "intr.h"
|
||||
#include "syscall/syscall.h"
|
||||
#include "proc/proc.h"
|
||||
#include "kprintf.h"
|
||||
#include "errors.h"
|
||||
|
||||
extern void hal_enable_syscallentry(void);
|
||||
extern void hal_syscallentry(void);
|
||||
|
||||
void hal_syscalldispatch(IntrStackFrame *frame) {
|
||||
uint64_t sysnum = frame->regs.rax;
|
||||
if (sysnum < SYSCALLS_MAX) {
|
||||
SyscallFn fn = SYSCALL_TABLE[sysnum];
|
||||
if (fn == NULL) {
|
||||
frame->regs.rax = E_BADSYSCALL;
|
||||
return;
|
||||
}
|
||||
int32_t ret = fn(frame->regs.rdi, frame->regs.rsi, frame->regs.rdx,
|
||||
frame->regs.r10, frame->regs.r8, frame->regs.r9);
|
||||
|
||||
if (sysnum == SYS_QUITPROC) {
|
||||
proc_sched((void *)frame);
|
||||
}
|
||||
frame->regs.rax = *(uint64_t *)&ret;
|
||||
}
|
||||
}
|
||||
|
||||
void hal_syscall_init(void) {
|
||||
hal_cpu_init(0);
|
||||
LocalCpuData *lcd = &HAL_CPUS[0];
|
||||
|
||||
hal_cpu_wrmsr(HAL_CPU_EFER, hal_cpu_rdmsr(HAL_CPU_EFER) | 0x1);
|
||||
hal_enable_syscallentry();
|
||||
|
||||
hal_cpu_wrmsr(HAL_CPU_GSBASE, (uint64_t)lcd);
|
||||
hal_cpu_wrmsr(HAL_CPU_KGSBASE, (uint64_t)lcd);
|
||||
hal_cpu_wrmsr(HAL_CPU_SFMASK, (uint64_t)0);
|
||||
|
||||
hal_cpu_wrmsr(HAL_CPU_LSTAR, (uint64_t)&hal_syscallentry);
|
||||
}
|
6
kernel/hal/x86_64/syscall.h
Normal file
6
kernel/hal/x86_64/syscall.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef HAL_SYSCALL_H_
|
||||
#define HAL_SYSCALL_H_
|
||||
|
||||
void hal_syscall_init(void);
|
||||
|
||||
#endif // HAL_SYSCALL_H_
|
48
kernel/hal/x86_64/syscall0.S
Normal file
48
kernel/hal/x86_64/syscall0.S
Normal file
@ -0,0 +1,48 @@
|
||||
#include "regs.S"
|
||||
|
||||
.extern hal_syscalldispatch
|
||||
|
||||
.global hal_enable_syscallentry
|
||||
hal_enable_syscallentry:
|
||||
movq $0xC0000080, %rcx
|
||||
rdmsr
|
||||
or $0x1, %eax
|
||||
wrmsr
|
||||
movq $0xC0000081, %rcx
|
||||
rdmsr
|
||||
movl $0x180008, %edx
|
||||
wrmsr
|
||||
ret
|
||||
|
||||
.global hal_syscallentry
|
||||
hal_syscallentry:
|
||||
cli
|
||||
swapgs
|
||||
|
||||
movq %rsp, %gs:0x8
|
||||
movq %gs:0x0, %rsp
|
||||
|
||||
pushq $0x23
|
||||
pushq %gs:0x8
|
||||
|
||||
swapgs
|
||||
|
||||
pushq %r11
|
||||
pushq $0x1b
|
||||
pushq %rcx
|
||||
|
||||
_push_regs
|
||||
|
||||
mov %rsp, %rdi
|
||||
mov $0x0, %rbp
|
||||
|
||||
call hal_syscalldispatch
|
||||
cli
|
||||
|
||||
_pop_regs
|
||||
|
||||
popq %rcx
|
||||
add $0x8, %rsp
|
||||
popq %r11
|
||||
popq %rsp
|
||||
sysret
|
@ -6,13 +6,6 @@
|
||||
#include "spinlock/spinlock.h"
|
||||
|
||||
#define kprintf(fmt, ...) \
|
||||
do { \
|
||||
spinlock_acquire(&TERM.spinlock); \
|
||||
printf_(fmt, ##__VA_ARGS__); \
|
||||
spinlock_release(&TERM.spinlock); \
|
||||
} while(0)
|
||||
|
||||
#define kprintf_unsafe(fmt, ...) \
|
||||
do { \
|
||||
printf_(fmt, ##__VA_ARGS__); \
|
||||
} while(0)
|
||||
|
@ -15,12 +15,6 @@
|
||||
|
||||
#define PROC_REAPER_FREQ 30
|
||||
|
||||
#define PROC_DIE() \
|
||||
do { \
|
||||
proc_killself(); \
|
||||
for(;;); \
|
||||
} while(0)
|
||||
|
||||
uint64_t pids = 0;
|
||||
uint64_t sched_ticks = 0;
|
||||
|
||||
@ -161,8 +155,16 @@ void proc_register(Proc *proc) {
|
||||
}
|
||||
|
||||
Proc *proc_nextready(void) {
|
||||
Proc *next = PROCS.current->next;
|
||||
Proc *proc = next == NULL ? PROCS.procs : next;
|
||||
Proc *proc = PROCS.current->next;
|
||||
for (;;) {
|
||||
if (proc == NULL) {
|
||||
proc = PROCS.procs;
|
||||
}
|
||||
if (proc->state != PROC_ZOMBIE) {
|
||||
return proc;
|
||||
}
|
||||
proc = proc->next;
|
||||
}
|
||||
return proc;
|
||||
}
|
||||
|
||||
@ -183,7 +185,7 @@ void proc_reaper(void) {
|
||||
while (vashead) {
|
||||
VasRange *tmp = vashead;
|
||||
vashead = vashead->next;
|
||||
hal_vmm_unmap_range(zombie->platformdata.cr3, tmp->virtstart, tmp->physstart, tmp->size);
|
||||
hal_vmm_unmap_range(VIRT(zombie->platformdata.cr3), tmp->virtstart, tmp->physstart, tmp->size);
|
||||
// first pmm mapping is for the elf itself
|
||||
if (i == 0) {
|
||||
pmm_free((uintptr_t)tmp->physstart, tmp->size / HAL_PAGE_SIZE);
|
||||
@ -218,6 +220,7 @@ void proc_sched(void *cpustate) {
|
||||
PROCS.current->state = PROC_RUNNING;
|
||||
|
||||
hal_cpu_wrmsr(HAL_CPU_FSBASE, PROCS.current->platformdata.fsbase);
|
||||
HAL_CPUS[0].syscall_kstack = VIRT(PROCS.current->platformdata.kstack);
|
||||
hal_switchproc(&PROCS.current->platformdata.trapframe, (void *)PROCS.current->platformdata.cr3);
|
||||
}
|
||||
|
||||
@ -239,11 +242,12 @@ void proc_idle(void) {
|
||||
}
|
||||
|
||||
void proc_status(void) {
|
||||
static const char *statuses[] = {"ready", "running", "zombie", "waiting"};
|
||||
for (;;) {
|
||||
spinlock_acquire(&PROCS.spinlock);
|
||||
Proc *head = PROCS.procs;
|
||||
while (head) {
|
||||
kprintf("%s %s\n", head->kern ? "kern" : "user", head->name);
|
||||
kprintf("%s %s %s\n", head->kern ? "kern" : "user", statuses[head->state], head->name);
|
||||
head = head->next;
|
||||
}
|
||||
kprintf("\n\n");
|
||||
|
@ -50,5 +50,12 @@ void proc_register(Proc *proc);
|
||||
Proc *proc_spawnkern(void (*ent)(void), char *name);
|
||||
Proc *proc_spawnuser(char *mountpoint, char *path);
|
||||
void proc_sched(void *cpustate);
|
||||
void proc_killself(void);
|
||||
|
||||
#define PROC_DIE() \
|
||||
do { \
|
||||
proc_killself(); \
|
||||
for(;;); \
|
||||
} while(0)
|
||||
|
||||
#endif // PROC_PROC_H_
|
||||
|
27
kernel/syscall/syscall.c
Normal file
27
kernel/syscall/syscall.c
Normal file
@ -0,0 +1,27 @@
|
||||
#include <stdint.h>
|
||||
#include "syscall.h"
|
||||
#include "errors.h"
|
||||
#include "dlmalloc/malloc.h"
|
||||
#include "kprintf.h"
|
||||
#include "proc/proc.h"
|
||||
|
||||
int32_t SYSCALL2(sys_debugprint, string1, len) {
|
||||
char *buf = dlmalloc(len);
|
||||
if (buf == NULL) {
|
||||
return E_NOMEMORY;
|
||||
}
|
||||
ksnprintf(buf, len, "%s", string1);
|
||||
kprintf("%s\n", buf);
|
||||
dlfree(buf);
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
int32_t SYSCALL0(sys_quitproc) {
|
||||
proc_killself();
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
SyscallFn SYSCALL_TABLE[SYSCALLS_MAX] = {
|
||||
[SYS_DEBUGPRINT] = &sys_debugprint,
|
||||
[SYS_QUITPROC] = &sys_quitproc,
|
||||
};
|
81
kernel/syscall/syscall.h
Normal file
81
kernel/syscall/syscall.h
Normal file
@ -0,0 +1,81 @@
|
||||
#ifndef SYSCALL_SYSCALL_H_
|
||||
#define SYSCALL_SYSCALL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "compiler/attr.h"
|
||||
|
||||
#define SYSCALLS_MAX 0xff
|
||||
|
||||
#define SYSCALL0(name) \
|
||||
name(UNUSED uint64_t _1, \
|
||||
UNUSED uint64_t _2, \
|
||||
UNUSED uint64_t _3, \
|
||||
UNUSED uint64_t _4, \
|
||||
UNUSED uint64_t _5, \
|
||||
UNUSED uint64_t _6 \
|
||||
)
|
||||
|
||||
#define SYSCALL1(name, arg1) \
|
||||
name(uint64_t arg1, \
|
||||
UNUSED uint64_t _2, \
|
||||
UNUSED uint64_t _3, \
|
||||
UNUSED uint64_t _4, \
|
||||
UNUSED uint64_t _5, \
|
||||
UNUSED uint64_t _6 \
|
||||
)
|
||||
|
||||
#define SYSCALL2(name, arg1, arg2) \
|
||||
name(uint64_t arg1, \
|
||||
uint64_t arg2, \
|
||||
UNUSED uint64_t _3, \
|
||||
UNUSED uint64_t _4, \
|
||||
UNUSED uint64_t _5, \
|
||||
UNUSED uint64_t _6 \
|
||||
)
|
||||
|
||||
#define SYSCALL3(name, arg1, arg2, arg3) \
|
||||
name(uint64_t arg1, \
|
||||
uint64_t arg2, \
|
||||
uint64_t arg3, \
|
||||
UNUSED uint64_t _4, \
|
||||
UNUSED uint64_t _5, \
|
||||
UNUSED uint64_t _6 \
|
||||
)
|
||||
|
||||
#define SYSCALL4(name, arg1, arg2, arg3, arg4) \
|
||||
name(uint64_t arg1, \
|
||||
uint64_t arg2, \
|
||||
uint64_t arg3, \
|
||||
uint64_t arg4, \
|
||||
UNUSED uint64_t _5, \
|
||||
UNUSED uint64_t _6 \
|
||||
)
|
||||
|
||||
#define SYSCALL5(name, arg1, arg2, arg3, arg4, arg5) \
|
||||
name(uint64_t arg1, \
|
||||
uint64_t arg2, \
|
||||
uint64_t arg3, \
|
||||
uint64_t arg4, \
|
||||
uint64_t arg5, \
|
||||
UNUSED uint64_t _6 \
|
||||
)
|
||||
|
||||
#define SYSCALL6(name, arg1, arg2, arg3, arg4, arg5, arg6) \
|
||||
name(uint64_t arg1, \
|
||||
uint64_t arg2, \
|
||||
uint64_t arg3, \
|
||||
uint64_t arg4, \
|
||||
uint64_t arg5, \
|
||||
uint64_t arg6 \
|
||||
)
|
||||
|
||||
enum {
|
||||
SYS_DEBUGPRINT = 1,
|
||||
SYS_QUITPROC = 2,
|
||||
};
|
||||
|
||||
typedef int32_t (*SyscallFn)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
|
||||
|
||||
extern SyscallFn SYSCALL_TABLE[SYSCALLS_MAX];
|
||||
|
||||
#endif // SYSCALL_SYSCALL_H_
|
@ -31,7 +31,6 @@ void term_doinit(void *addr) {
|
||||
}
|
||||
|
||||
void term_init(void *addr) {
|
||||
spinlock_init(&TERM.spinlock);
|
||||
term_doinit(addr);
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,6 @@
|
||||
|
||||
typedef struct {
|
||||
struct flanterm_context *ftctx;
|
||||
SpinLock spinlock;
|
||||
} Term;
|
||||
|
||||
extern Term TERM;
|
||||
|
@ -2,4 +2,4 @@
|
||||
|
||||
set -x
|
||||
|
||||
qemu-system-x86_64 -cpu qemu64,+pdpe1gb -m 4G -cdrom mop2.iso -boot d -serial stdio $@
|
||||
qemu-system-x86_64 -cpu IvyBridge -m 4G -cdrom mop2.iso -boot d -serial stdio $@
|
||||
|
@ -1,7 +1,6 @@
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS {
|
||||
/* . = 0xffff000000000000; */
|
||||
. = 0x0000000000000000;
|
||||
|
||||
.rodata ALIGN(4K):
|
||||
|
@ -16,7 +16,7 @@ all: $(TARGET)
|
||||
|
||||
hello: $(OBJ)
|
||||
$(LD) $^ $(LDFLAGS) -o $@
|
||||
echo $(realpath $@) >> $(FILES)
|
||||
echo $(realpath hello) >> $(FILES)
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ) $(TARGET)
|
||||
|
@ -1,6 +1,18 @@
|
||||
.section .data
|
||||
STRING:
|
||||
.string "Hello World from userspace"
|
||||
STRING_LEN:
|
||||
.quad . - STRING
|
||||
|
||||
.section .text
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
.spin:
|
||||
jmp .spin
|
||||
movq $1, %rax
|
||||
lea STRING(%rip), %rdi
|
||||
lea STRING_LEN(%rip), %rsi
|
||||
syscall
|
||||
|
||||
movq $2, %rax
|
||||
syscall
|
||||
|
||||
|
Reference in New Issue
Block a user