summaryrefslogtreecommitdiff
path: root/src/kernel/arch/i386/sysenter.c
blob: 1aee254167c32c85e224efd52186c87bfdd98c2c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <kernel/arch/generic.h>
#include <kernel/arch/i386/interrupts/irq.h>
#include <kernel/arch/i386/sysenter.h>
#include <kernel/proc.h>
#include <shared/syscalls.h>

struct registers _sysexit_regs;

void sysexit(struct registers regs) {
	_sysexit_regs = regs;
	_sysexit_regs.ecx = (uintptr_t) regs.esp;
	_sysexit_regs.edx = (uintptr_t) regs.eip;
	_sysexit_real();
	__builtin_unreachable();
}

_Noreturn void sysenter_stage2(void) {
	uint64_t val;
	struct registers *regs = &process_current->regs;

	*regs = _sysexit_regs; // save the registers
	regs->esp = (userptr_t) regs->ecx; // fix them up
	regs->eip = (userptr_t) regs->edx;

	irq_interrupt_flag(false);

	val = _syscall(regs->eax, regs->ebx,
	               regs->esi, regs->edi, (uintptr_t)regs->ebp);
	if (process_current->state == PS_RUNNING) { // TODO move to _syscall()
		regs_savereturn(&process_current->regs, val);
		process_switch(process_current); // TODO process_resume
	} else {
		process_switch_any();
	}
}