/
syscall.cpp
138 lines (114 loc) · 3.81 KB
/
syscall.cpp
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// PhoeniX OS System calls subsystem
// Copyright © 2017 Yury Popov a.k.a. PhoeniX
#include "syscall.hpp"
#include "processmanager.hpp"
#include "./syscall_hash.hpp"
#include "./syscall_setup.hpp"
static void syscall_puts(uintptr_t strptr) {
Process *process = ProcessManager::getManager()->currentProcess();
const char *str = process->readString(strptr);
Display::getInstance()->write(str);
delete str;
}
static void syscall_exit(int code) {
ProcessManager *manager = ProcessManager::getManager();
Process *process = manager->currentProcess();
void *rsp; asm volatile("mov %%rsp, %q0; and $~0xFFF, %q0":"=r"(rsp));
Pagetable::Entry *pt; asm volatile("mov %%cr3, %q0":"=r"(pt));
Pagetable::Entry *pte = Pagetable::Entry::find(rsp, pt);
asm volatile(
"callq _ZN7Process4exitEi;"
"sti; movq $0, %q2;"
"jmp _ZN14ProcessManager12process_loopEv"
::"D"(process), "S"(code), "a"(pte)
);
}
static void syscall_ioprovide(const char *path, const void *ptr) {
Process *process = ProcessManager::getManager()->currentProcess();
char *str = process->readString(uintptr_t(path));
printf("ioprovide [%p] [%s]\n", ptr, str);
delete str;
}
#define SYSCALL_ENT(name) { \
syscall_hash(#name), \
reinterpret_cast<void*>(syscall_ ## name) \
}
static const struct {
uint64_t hash;
void *entry;
} PACKED syscall_map[] = {
SYSCALL_ENT(puts),
SYSCALL_ENT(exit),
SYSCALL_ENT(ioprovide),
{0, nullptr}
};
#undef SYSCALL_ENT
static uint64_t syscall_index(uint64_t hash) {
static const size_t num = sizeof(syscall_map) / sizeof(*syscall_map);
for (uint64_t idx = 0; idx < num - 1; idx++) {
if (syscall_map[idx].hash == hash) return idx;
}
return static_cast<uint64_t>(-1);
}
uint64_t Syscall::callByName(const char *name) {
uint64_t hash = syscall_hash(name);
if (syscall_index(hash) == uint64_t(-1)) return 0;
return hash;
}
void __attribute((naked)) Syscall::wrapper() {
asm volatile(
// Save registers
"push %rbx;"
"push %r11;"
"push %r12;"
"push %r13;"
"push %r14;"
"push %r15;"
// Save pagetable
"mov %cr3, %rbx;"
// Set stack to absolute address
"mov %rsp, %r12; shr $39, %r12; and $0x1FF, %r12;" // r12 = ptx
"mov (%rbx,%r12,8), %r13; and $~0xFFF, %r13; btr $63, %r13;" // rbx = pt, r12 = pte
"mov %rsp, %r12; shr $30, %r12; and $0x1FF, %r12;" // r12 = pdx
"mov (%r13,%r12,8), %r13; and $~0xFFF, %r13; btr $63, %r13;" // r13 = pde
"mov %rsp, %r12; shr $21, %r12; and $0x1FF, %r12;" // r12 = pdpx
"mov (%r13,%r12,8), %r13; and $~0xFFF, %r13; btr $63, %r13;" // r13 = pdpe
"mov %rsp, %r12; shr $12, %r12; and $0x1FF, %r12;" // r12 = pml4x
"mov (%r13,%r12,8), %r13; and $~0xFFF, %r13; btr $63, %r13;" // r13 = pml4e
// Save stack
"mov %rsp, %r12;"
"mov %rsp, %r14; and $0xFFF, %r14; add %r14, %r13; mov %r13, %rsp;"
// Set kernel pagetable
"_wrapper_mov_cr3: movabsq $0, %r13; mov %r13, %cr3;"
// Find syscall handler
"lea _ZL11syscall_map(%rip), %r13;"
"1:"
"cmp %rax, (%r13);"
"je 1f;"
"cmpq $0, (%r13);"
"je 2f;"
"add $16, %r13;"
"jmp 1b;"
"1:"
"mov %rcx, %r14; callq *8(%r13); mov %r14, %rcx;"
// Restore process stack & pagetable
"mov %r12, %rsp; mov %rbx, %cr3;"
// Restore registers
"pop %r15;"
"pop %r14;"
"pop %r13;"
"pop %r12;"
"pop %r11;"
"pop %rbx;"
// Return to ring3
"sysretq;"
"2: ud2;"
);
}
void Syscall::setup() {
asm volatile("mov %%cr3, %%rax; mov %%rax, 2 + _wrapper_mov_cr3(%%rip)":::"%rax");
wrmsr(MSR_STAR, uint64_t(0x10) << 48 | uint64_t(0x8) << 32);
wrmsr(MSR_LSTAR, uintptr_t(wrapper));
wrmsr(MSR_SFMASK, MSR_SFMASK_IE);
wrmsr(MSR_EFER, rdmsr(MSR_EFER) | MSR_EFER_SCE | MSR_EFER_NXE);
}