/
process.cpp
375 lines (351 loc) · 11.4 KB
1
// PhoeniX OS Process subsystem
2
// Copyright © 2017 Yury Popov a.k.a. PhoeniX
3
4
#include "process.hpp"
5
6
#include "processmanager.hpp"
7
#include "syscall.hpp"
8
#include "acpi.hpp"
9
10
11
using PTE = Pagetable::Entry;
12
13
14
15
16
Process::Process() :
id(uint64_t(-1)), entry(0),
_aslrCode(RAND::get<uintptr_t>(0x80000000llu, 0x100000000llu) << 12),
_aslrStack(RAND::get<uintptr_t>(0x40000000llu, 0x80000000llu) << 12),
_syscallPage(0), _syscallNum(0),
17
name(nullptr),
18
19
pagetable(nullptr) {
iomap[0] = iomap[1] = nullptr;
20
}
21
22
Process::~Process() {
23
void *rsp; asm volatile("mov %%rsp, %q0; and $~0xFFF, %q0":"=r"(rsp));
24
if (pagetable != nullptr) {
25
PTE addr;
26
for (uintptr_t ptx = 0; ptx < 512; ptx++) {
27
28
29
addr = pagetable[ptx];
if (!addr.present)
continue;
30
PTE *ppde = addr.getPTE();
31
for (uintptr_t pdx = 0; pdx < 512; pdx++) {
32
33
34
addr = ppde[pdx];
if (!addr.present)
continue;
35
PTE *pppde = addr.getPTE();
36
for (uintptr_t pdpx = 0; pdpx < 512; pdpx++) {
37
38
39
addr = pppde[pdpx];
if (!addr.present)
continue;
40
PTE *ppml4e = addr.getPTE();
41
for (uintptr_t pml4x = 0; pml4x < 512; pml4x++) {
42
43
44
addr = ppml4e[pml4x];
if (!addr.present)
continue;
45
void *page = addr.getPtr();
46
uintptr_t ptaddr = ((ptx << (12 + 9 + 9 + 9))
47
| (pdx << (12 + 9 + 9))
48
49
50
| (pdpx << (12 + 9)) | (pml4x << (12)));
if (page == rsp) continue;
if (uintptr_t(page) == ptaddr) continue;
51
Pagetable::free(page);
52
}
53
Pagetable::free(ppml4e);
54
}
55
Pagetable::free(pppde);
56
}
57
Pagetable::free(ppde);
58
}
59
Pagetable::free(pagetable);
60
}
61
62
for (size_t i = 0; i < symbols.getCount(); i++) {
delete[] symbols[i].name;
63
}
64
65
66
for (size_t i = 0; i < threads.getCount(); i++) {
ProcessManager::getManager()->dequeueThread(threads[i]);
delete threads[i];
67
}
68
delete name;
69
}
70
71
PTE* Process::addPage(uintptr_t vaddr, void* paddr, uint8_t flags) {
72
73
74
75
uint16_t ptx = (vaddr >> (12 + 9 + 9 + 9)) & 0x1FF;
uint16_t pdx = (vaddr >> (12 + 9 + 9)) & 0x1FF;
uint16_t pdpx = (vaddr >> (12 + 9)) & 0x1FF;
uint16_t pml4x = (vaddr >> (12)) & 0x1FF;
76
if (pagetable == nullptr) {
77
pagetable = static_cast<PTE*>(Pagetable::alloc());
78
addPage(uintptr_t(pagetable), pagetable, 5);
79
}
80
81
82
if (!pagetable[ptx].present) {
pagetable[ptx] = PTE(Pagetable::alloc(), 7);
addPage(pagetable[ptx].getUintPtr(), pagetable[ptx].getPtr(), 5);
83
}
84
85
86
87
PTE *pde = pagetable[ptx].getPTE();
if (!pde[pdx].present) {
pde[pdx] = PTE(Pagetable::alloc(), 7);
addPage(pde[pdx].getUintPtr(), pde[pdx].getPtr(), 5);
88
}
89
90
91
92
PTE *pdpe = pde[pdx].getPTE();
if (!pdpe[pdpx].present) {
pdpe[pdpx] = PTE(Pagetable::alloc(), 7);
addPage(pdpe[pdpx].getUintPtr(), pdpe[pdpx].getPtr(), 5);
93
}
94
95
PTE *pml4e = pdpe[pdpx].getPTE();
pml4e[pml4x] = PTE(paddr, flags | 1);
96
return &pml4e[pml4x];
97
98
99
}
uintptr_t Process::addSection(SectionType type, size_t size) {
100
101
102
if (size == 0)
return 0;
size_t pages = (size >> 12) + 1;
103
104
105
106
107
108
109
uintptr_t vaddr;
if (type != SectionTypeStack) {
vaddr = _aslrCode;
} else {
vaddr = _aslrStack;
}
110
for (uintptr_t caddr = vaddr; caddr < vaddr + size; caddr += 0x1000) {
111
if (getPhysicalAddress(vaddr) != nullptr) {
112
vaddr += 0x1000;
113
caddr = vaddr - 0x1000;
114
115
116
117
118
119
120
}
}
uintptr_t addr = vaddr;
while (pages-- > 0) {
uint8_t flags = 4;
switch (type) {
case SectionTypeCode:
121
case SectionTypeROData:
122
123
124
125
126
127
128
break;
case SectionTypeData:
case SectionTypeBSS:
case SectionTypeStack:
flags |= 2;
break;
}
129
addPage(vaddr, Pagetable::alloc(), flags)->nx = type != SectionTypeCode;
130
131
132
vaddr += 0x1000;
}
return addr;
133
134
}
void Process::addSymbol(const char *name, uintptr_t ptr) {
135
symbols.insert() = { ptr, klib::strdup(name) };
136
137
}
void Process::setEntryAddress(uintptr_t ptr) {
138
entry = ptr;
139
140
}
uintptr_t Process::getSymbolByName(const char* name) {
141
for (size_t i = 0; i < symbols.getCount(); i++) {
142
if (klib::strcmp(symbols[i].name, name) == 0)
143
return symbols[i].ptr;
144
145
}
return 0;
146
}
147
148
149
150
151
152
153
154
155
156
157
158
159
struct SyscallEntry {
const uint8_t _pre[2] = {
// movabsq ..., %rax
0x48, 0xb8,
};
const uint64_t syscall_id;
const uint8_t _post[3] = {
// syscallq; ret
0x0f, 0x05, 0xc3,
};
explicit SyscallEntry(uint64_t idx) : syscall_id(idx) {}
} PACKED;
160
uintptr_t Process::linkLibrary(const char* funcname) {
161
162
163
164
if (klib::strcmp(funcname, "kptr_acpi_rsdp") == 0) {
return uintptr_t(ACPI::getController()->getRSDPAddr());
}
165
166
167
uintptr_t ptr = getSymbolByName(funcname);
if (ptr != 0) return ptr;
168
169
uint64_t syscall_id;
if ((syscall_id = Syscall::callByName(funcname)) != 0) {
170
171
172
173
174
175
176
static const constexpr size_t countInPage = 0x1000 / sizeof(SyscallEntry);
if (_syscallPage == 0 || _syscallNum == countInPage) {
_syscallPage = addSection(SectionTypeCode, sizeof(SyscallEntry) * countInPage);
_syscallNum = 0;
}
struct SyscallEntry call(syscall_id);
ptr = _syscallPage + (_syscallNum++) * sizeof(SyscallEntry);
177
178
179
writeData(ptr, &call, sizeof(call));
addSymbol(funcname, ptr);
}
180
181
182
return ptr;
}
183
184
void Process::writeData(uintptr_t address, const void* src, size_t size) {
const uint8_t *ptr = static_cast<const uint8_t*>(src);
185
186
while (size > 0) {
void *dest = getPhysicalAddress(address);
187
size_t limit = 0x1000 - (uintptr_t(dest) & 0xFFF);
188
size_t count = klib::min(size, limit);
189
Memory::copy(dest, ptr, count);
190
size -= count;
191
ptr += count;
192
193
address += count;
}
194
}
195
void Process::readData(void* dst, uintptr_t address, size_t size) const {
196
char *ptr = static_cast<char*>(dst);
197
198
while (size > 0) {
void *src = getPhysicalAddress(address);
199
size_t limit = 0x1000 - (uintptr_t(src) & 0xFFF);
200
size_t count = klib::min(size, limit);
201
Memory::copy(ptr, src, count);
202
size -= count;
203
ptr += count;
204
205
address += count;
}
206
}
207
char *Process::readString(uintptr_t address) const {
208
size_t length = 0;
209
const char *src = static_cast<const char*>(getPhysicalAddress(address));
210
size_t limit = 0x1000 - (uintptr_t(src) & 0xFFF);
211
212
213
while (limit-- && src[length] != 0) {
length++;
if (limit == 0) {
214
src = static_cast<const char*>(getPhysicalAddress(address + length));
215
216
217
218
limit += 0x1000;
}
}
if (length == 0)
219
return nullptr;
220
char *buf = new char[length + 1]();
221
222
readData(buf, address, length + 1);
return buf;
223
}
224
void *Process::getPhysicalAddress(uintptr_t ptr) const {
225
226
if (pagetable == nullptr)
return nullptr;
227
uintptr_t off = ptr & 0xFFF;
228
PTE *addr = PTE::find(ptr, pagetable);
229
if (!addr || !addr->present) return nullptr;
230
return reinterpret_cast<void*>(addr->getUintPtr() + off);
231
232
}
void Process::addThread(Thread *thread, bool suspended) {
233
234
235
236
if (thread->stack_top == 0) {
thread->stack_top = addSection(SectionTypeStack, 0x7FFF) + 0x8000;
thread->regs.rsp = thread->stack_top;
}
237
thread->suspend_ticks = suspended ? uint64_t(-1) : 0;
238
239
threads.add(thread);
240
ProcessManager::getManager()->queueThread(this, thread);
241
}
242
243
244
245
246
247
248
249
250
251
252
253
254
255
void Process::allowIOPorts(uint16_t min, uint16_t max) {
for (uint16_t i = 0; i <= (max - min); i++) {
uint16_t port = min + i;
size_t space = port / 8 / 0x1000;
size_t byte = (port / 8) & 0xFFF;
size_t bit = port % 8;
uint8_t *map;
if (!(map = reinterpret_cast<uint8_t*>(iomap[space]))) {
map = reinterpret_cast<uint8_t*>(iomap[space] = Pagetable::alloc());
Memory::fill(map, 0xFF, 0x1000);
}
map[byte] &= ~(1 << bit);
}
}
256
void Process::startup() {
257
258
DTREG gdt = { 0, nullptr };
DTREG idt = { 0, nullptr };
259
asm volatile("sgdtq %0; sidtq %1":"=m"(gdt), "=m"(idt));
260
261
static const uintptr_t KB4 = 0xFFFFFFFFFFFFF000;
262
263
for (uintptr_t addr = uintptr_t(gdt.addr) & KB4;
addr < (uintptr_t(gdt.addr) + gdt.limit); addr += 0x1000) {
264
addPage(addr, reinterpret_cast<void*>(addr), 1);
265
}
266
267
for (uintptr_t addr = uintptr_t(idt.addr) & KB4;
addr < (uintptr_t(idt.addr) + idt.limit); addr += 0x1000) {
268
addPage(addr, reinterpret_cast<void*>(addr), 1);
269
}
270
Interrupts::REC64 *recs = static_cast<Interrupts::REC64*>(idt.addr);
271
272
uintptr_t page = 0;
for (uint16_t i = 0; i < 0x100; i++) {
273
274
275
uintptr_t handler = (uintptr_t(recs[i].offset_low)
| (uintptr_t(recs[i].offset_middle) << 16)
| (uintptr_t(recs[i].offset_high) << 32));
276
277
if (page != (handler & KB4)) {
page = handler & KB4;
278
addPage(page, reinterpret_cast<void*>(page), 1);
279
280
}
}
281
uintptr_t handler, sc_wrapper;
282
asm volatile("lea __interrupt_wrap(%%rip), %q0":"=r"(handler));
283
asm volatile("lea _ZN7Syscall7wrapperEv(%%rip), %q0":"=r"(sc_wrapper));
284
handler &= KB4;
285
sc_wrapper &= KB4;
286
addPage(handler, reinterpret_cast<void*>(handler), 1);
287
addPage(handler + 0x1000, reinterpret_cast<void*>(handler + 0x1000), 1);
288
addPage(sc_wrapper, reinterpret_cast<void*>(sc_wrapper), 1);
289
addPage(sc_wrapper + 0x1000, reinterpret_cast<void*>(sc_wrapper + 0x1000), 1);
290
291
GDT::Entry *gdt_ent = reinterpret_cast<GDT::Entry*>(uintptr_t(gdt.addr) + 8 * 3);
GDT::Entry *gdt_top = reinterpret_cast<GDT::Entry*>(uintptr_t(gdt.addr) + gdt.limit);
292
293
294
295
296
297
298
299
300
if (!iomap[0]) {
iomap[0] = Pagetable::alloc();
Memory::fill(iomap[0], 0xFF, 0x1000);
}
if (!iomap[1]) {
iomap[1] = Pagetable::alloc();
Memory::fill(iomap[1], 0xFF, 0x1000);
}
301
302
while (gdt_ent < gdt_top) {
303
uintptr_t base = gdt_ent->getBase();
304
if ((gdt_ent->type != 0x9) && (gdt_ent->type != 0xB)) {
305
gdt_ent++;
306
continue;
307
}
308
309
310
311
GDT::SystemEntry *sysent = reinterpret_cast<GDT::SystemEntry*>(gdt_ent);
base = sysent->getBase();
312
uintptr_t page = base & KB4;
313
314
315
addPage(page, reinterpret_cast<void*>(page), 1);
addPage(page + 0x1000, iomap[0], 1);
addPage(page + 0x2000, iomap[1], 1);
316
317
TSS64_ENT *tss = reinterpret_cast<TSS64_ENT*>(base);
318
319
uintptr_t stack = tss->ist[0];
page = stack - 0x1000;
320
addPage(page, reinterpret_cast<void*>(page), 3);
321
gdt_ent = reinterpret_cast<GDT::Entry*>(sysent + 1);
322
323
}
324
325
326
Thread *thread = new Thread();
thread->regs.rip = entry;
thread->regs.rflags = 0;
327
id = (ProcessManager::getManager())->registerProcess(this);
328
addThread(thread, false);
329
}
330
331
void Process::exit(int code) {
332
(void)code; // TODO: handle
333
334
335
for (size_t i = 0; i < threads.getCount(); i++) {
ProcessManager::getManager()->dequeueThread(threads[i]);
}
336
ProcessManager::getManager()->exitProcess(this, code);
337
338
delete this;
}
339
340
341
342
343
344
345
const char *Process::getName() const { return name; }
void Process::setName(const char *newname) {
delete name;
name = newname ? klib::strdup(newname) : nullptr;
}
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
void Process::print_stacktrace(uintptr_t base, const Process *process) {
struct stackframe {
struct stackframe* rbp;
uintptr_t rip;
} __attribute__((packed));
printf("STACK TRACE:");
struct stackframe tmpframe;
const struct stackframe *frame;
if (base) {
frame = reinterpret_cast<struct stackframe*>(base);
} else {
asm volatile("mov %%rbp, %q0":"=r"(frame)::);
}
size_t lim = 10;
361
while (lim-- && frame != nullptr) {
362
363
364
365
366
367
368
369
370
371
372
373
374
375
if (process) {
process->readData(&tmpframe.rbp, uintptr_t(frame), sizeof(uintptr_t));
if (tmpframe.rbp) {
process->readData(&tmpframe.rip, uintptr_t(frame)+sizeof(uintptr_t), sizeof(uintptr_t));
} else {
break;
}
frame = &tmpframe;
}
printf(" [%p]:%p", frame->rbp, reinterpret_cast<void*>(frame->rip));
frame = frame->rbp;
}
printf("\n");
}