summaryrefslogtreecommitdiff
path: root/src/kernel/arch/i386/sysenter.c
blob: f3f5987f30cfa47e5c87a57b526c9e6dd593d992 (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
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <kernel/arch/generic.h>
#include <kernel/proc.h>

struct registers_pushad _sysexit_regs; // a hack

extern void _sysexit_real();

void sysexit(struct registers regs) {
	_sysexit_regs = (struct registers_pushad) {
		.eax = regs.eax,
		.ebx = regs.ebx,
		.ebp = regs.ebp,
		.esi = regs.esi,
		.edi = regs.edi,

		// sysexit args
		.ecx = regs.esp,
		.edx = regs.eip,

		// ESP doesn't matter
	};
	_sysexit_real();
}

void sysenter_stage2(int edi, int esi, void *ebp, void *esp,
                     int ebx, int edx, int   ecx, int   eax)
{
	uint64_t val;
	process_current->regs = (struct registers) {
		// EAX and EDX will get overriden with the return value later on

		.eax = eax,
		.ecx = ecx,
		.edx = edx,
		.ebx = ebx,
		.esi = esi,
		.edi = edi,

		.esp = (void*) ecx, // not a typo, part of my calling convention
		.eip = (void*) edx, // ^
		.ebp = ebp,
	};

	val = syscall_handler(eax, ebx, esi, edi);
	regs_savereturn(&process_current->regs, val);

	process_switch(process_current); // TODO process_resume
}