parent
2d4f76a5dd
commit
b32c12b311
@ -0,0 +1,16 @@ |
||||
bits 64 |
||||
org 0x400000 |
||||
|
||||
section .text |
||||
mov rax, 1 |
||||
mov rdi, 1 |
||||
lea rsi, [rel msg] |
||||
mov rdx, 14 |
||||
syscall |
||||
|
||||
mov rax, 60 |
||||
xor rdi, rdi |
||||
syscall |
||||
|
||||
section .data |
||||
msg: db "Hello, ring 3!", 10 |
||||
@ -0,0 +1,68 @@ |
||||
#include "src/gdt.h" |
||||
#include "src/tss.h" |
||||
#include <stdint.h> |
||||
|
||||
typedef struct { |
||||
uint16_t limit_low; |
||||
uint16_t base_low; |
||||
uint8_t base_mid; |
||||
uint8_t access; |
||||
uint8_t flags_limit_high; |
||||
uint8_t base_high; |
||||
} __attribute__((packed)) gdt_entry_t; |
||||
|
||||
typedef struct { |
||||
gdt_entry_t base; |
||||
uint32_t base_upper; |
||||
uint32_t reserved; |
||||
} __attribute__((packed)) gdt_system_entry_t; |
||||
|
||||
typedef struct { |
||||
gdt_entry_t gdt[6]; |
||||
gdt_system_entry_t tss_entry; |
||||
} __attribute__((packed)) gdt_table_t; |
||||
|
||||
typedef struct { |
||||
uint16_t limit; |
||||
uint64_t offset; |
||||
} __attribute__((packed)) gdt_descriptor_t; |
||||
|
||||
static gdt_table_t gdt; |
||||
static gdt_descriptor_t desc; |
||||
|
||||
static void set_entry(gdt_entry_t *e, uint8_t access, uint8_t flags) { |
||||
e->limit_low = 0xFFFF; |
||||
e->base_low = 0; |
||||
e->base_mid = 0; |
||||
e->access = access; |
||||
e->flags_limit_high = flags | 0x0F; |
||||
e->base_high = 0; |
||||
} |
||||
|
||||
static void set_tss_entry(void *base) { |
||||
uint64_t ibase = (uint64_t)base; |
||||
gdt.tss_entry.base.limit_low = sizeof(tss_t) - 1; |
||||
gdt.tss_entry.base.base_low = ibase & 0xFFFF; |
||||
gdt.tss_entry.base.base_mid = (ibase >> 16) & 0xFF; |
||||
gdt.tss_entry.base.access = 0x89; // present, type=TSS available
|
||||
gdt.tss_entry.base.flags_limit_high = 0x00; |
||||
gdt.tss_entry.base.base_high = (ibase >> 24) & 0xFF; |
||||
gdt.tss_entry.base_upper = ibase >> 32; |
||||
gdt.tss_entry.reserved = 0; |
||||
} |
||||
|
||||
void gdt_init() { |
||||
gdt.gdt[0] = (gdt_entry_t){0}; |
||||
set_entry(&gdt.gdt[1], 0x9A, 0xCF); // present, ring 0, code, executable, readable, 32-bit, 4KB granularity
|
||||
set_entry(&gdt.gdt[2], 0x9A, 0xA0); // present, ring 0, code, executable, readable, 64-bit
|
||||
set_entry(&gdt.gdt[3], 0x92, 0x00); // present, ring 0, data, writable
|
||||
set_entry(&gdt.gdt[4], 0xF2, 0x00); // present, ring 3, data, writable
|
||||
set_entry(&gdt.gdt[5], 0xFA, 0xA0); // present, ring 3, code, executable, readable, 64-bit
|
||||
set_tss_entry(&tss); |
||||
|
||||
desc.limit = sizeof(gdt) - 1; |
||||
desc.offset = (uint64_t)&gdt; |
||||
|
||||
__asm__ volatile("lgdt %0" : : "m"(desc)); |
||||
__asm__ volatile("ltr %0" : : "r"((uint16_t)TSS_SEL)); |
||||
} |
||||
@ -0,0 +1,12 @@ |
||||
#pragma once |
||||
|
||||
#define OBSOLETE_CS 0x08 |
||||
#define KERNEL_CS (OBSOLETE_CS + 0x08) |
||||
#define KERNEL_DS (KERNEL_CS + 0x08) |
||||
#define USER_DS_BASE (KERNEL_DS + 0x08) |
||||
#define USER_DS (USER_DS_BASE | 3) |
||||
#define USER_CS_BASE (USER_DS_BASE + 0x08) |
||||
#define USER_CS (USER_CS_BASE | 3) |
||||
#define TSS_SEL (USER_CS_BASE + 0x08) |
||||
|
||||
void gdt_init(); |
||||
@ -0,0 +1,112 @@ |
||||
#include "src/process.h" |
||||
#include "src/gdt.h" |
||||
#include "src/memory.h" |
||||
#include "src/panic.h" |
||||
#include "src/path.h" |
||||
#include "src/tss.h" |
||||
|
||||
process_t *current_process; |
||||
|
||||
process_t *process_create(const process_t *parent, const uint8_t *code, uint64_t size) { |
||||
ASSERT(size <= USER_VIRTUAL_HEAP - USER_VIRTUAL_CODE, "process_create: binary too big"); |
||||
|
||||
process_t *proc = memory_allocate(sizeof(process_t)); |
||||
|
||||
proc->kernel_stack = (uint8_t *)memory_allocate(PAGE_SIZE) + PAGE_SIZE; |
||||
|
||||
proc->pml4 = PHYS_TO_VIRT(memory_page_allocate()); |
||||
memory_set(0, PAGE_SIZE / 2, proc->pml4); |
||||
memory_copy((uint64_t *)KERNEL_PML4 + 256, PAGE_SIZE / 2, proc->pml4 + 256); |
||||
|
||||
memory_page_map(proc->pml4, (void *)USER_VIRTUAL_STACK, memory_page_allocate(), PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER); |
||||
|
||||
for (uint64_t page = 0; size > 0; page++) { |
||||
void *p = memory_page_allocate(); |
||||
uint64_t s = size < PAGE_SIZE ? size : PAGE_SIZE; |
||||
memory_page_map(proc->pml4, (void *)(USER_VIRTUAL_CODE + page * PAGE_SIZE), p, PAGE_PRESENT | PAGE_USER); |
||||
memory_copy(code, s, PHYS_TO_VIRT(p)); |
||||
code += s; |
||||
size -= s; |
||||
} |
||||
|
||||
for (uint64_t page = 0; page < HEAP_PAGE_COUNT; page++) { |
||||
memory_page_map(proc->pml4, (void *)(USER_VIRTUAL_HEAP + page * PAGE_SIZE), memory_page_allocate(), |
||||
PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER); |
||||
} |
||||
|
||||
proc->cwd = memory_allocate(sizeof(path_t)); |
||||
proc->cwd->depth = parent->cwd->depth; |
||||
for (uint8_t i = 0; i < parent->cwd->depth; i++) { |
||||
proc->cwd->stack[i] = fs_open_again(parent->cwd->stack[i]); |
||||
} |
||||
|
||||
proc->root = parent->root; |
||||
proc->stdin = parent->stdin; |
||||
proc->stdout = parent->stdout; |
||||
|
||||
return proc; |
||||
} |
||||
|
||||
void process_run(process_t *proc) { |
||||
current_process = proc; |
||||
tss.rsp0 = (uint64_t)proc->kernel_stack; |
||||
|
||||
__asm__ volatile("mov %0, %%cr3" : : "r"(VIRT_TO_PHYS(proc->pml4)) : "memory"); |
||||
|
||||
__asm__ volatile("push %0\n" // ss
|
||||
"push %1\n" // rsp
|
||||
"push %2\n" // rflags
|
||||
"push %3\n" // cs
|
||||
"push %4\n" // rip
|
||||
"iretq" |
||||
: |
||||
: "r"((uint64_t)USER_DS), "r"(USER_VIRTUAL_STACK + PAGE_SIZE), "r"((uint64_t)USER_RFLAGS), "r"((uint64_t)USER_CS), |
||||
"r"(USER_VIRTUAL_CODE) |
||||
: "memory"); |
||||
} |
||||
|
||||
void process_destroy(process_t *proc) { |
||||
path_close(proc->cwd); |
||||
|
||||
for (uint16_t pml4i = 0; pml4i < 256; pml4i++) { |
||||
if (!(proc->pml4[pml4i] & PAGE_PRESENT)) { |
||||
continue; |
||||
} |
||||
|
||||
uint64_t *pdpt = PHYS_TO_VIRT(proc->pml4[pml4i] & ~(uint64_t)0xFFF); |
||||
for (uint16_t pdpti = 0; pdpti < 512; pdpti++) { |
||||
if (!(pdpt[pdpti] & PAGE_PRESENT)) { |
||||
continue; |
||||
} |
||||
|
||||
uint64_t *pd = PHYS_TO_VIRT(pdpt[pdpti] & ~(uint64_t)0xFFF); |
||||
for (uint16_t pdi = 0; pdi < 512; pdi++) { |
||||
if (!(pd[pdi] & PAGE_PRESENT)) { |
||||
continue; |
||||
} |
||||
|
||||
if (pd[pdi] & PAGE_HUGE) { |
||||
memory_page_free((void *)(pd[pdi] & ~(uint64_t)0xFFF)); |
||||
continue; |
||||
} |
||||
|
||||
uint64_t *pt = PHYS_TO_VIRT(pd[pdi] & ~(uint64_t)0xFFF); |
||||
for (uint16_t pti = 0; pti < 512; pti++) { |
||||
if (!(pt[pti] & PAGE_PRESENT)) { |
||||
continue; |
||||
} |
||||
memory_page_free((void *)(pt[pti] & ~(uint64_t)0xFFF)); |
||||
} |
||||
memory_page_free((void *)(pd[pdi] & ~(uint64_t)0xFFF)); |
||||
} |
||||
memory_page_free((void *)(pdpt[pdpti] & ~(uint64_t)0xFFF)); |
||||
} |
||||
memory_page_free((void *)(proc->pml4[pml4i] & ~(uint64_t)0xFFF)); |
||||
} |
||||
|
||||
memory_page_free((void *)VIRT_TO_PHYS(proc->pml4)); |
||||
|
||||
memory_free(proc->kernel_stack); |
||||
|
||||
memory_free(proc); |
||||
} |
||||
@ -0,0 +1,39 @@ |
||||
bits 64 |
||||
|
||||
extern tss |
||||
extern syscall_dispatch |
||||
|
||||
global syscall_entry |
||||
|
||||
syscall_entry: |
||||
mov [user_rsp_tmp], rsp |
||||
mov rsp, [tss + 4] |
||||
|
||||
push rcx |
||||
push r11 |
||||
push rbp |
||||
push rbx |
||||
push r12 |
||||
push r13 |
||||
push r14 |
||||
push r15 |
||||
|
||||
mov rcx, rdx ; arg3 |
||||
mov rdx, rsi ; arg2 |
||||
mov rsi, rdi ; arg1 |
||||
mov rdi, rax ; syscall number |
||||
call syscall_dispatch |
||||
|
||||
pop r15 |
||||
pop r14 |
||||
pop r13 |
||||
pop r12 |
||||
pop rbx |
||||
pop rbp |
||||
pop r11 |
||||
pop rcx |
||||
|
||||
mov rsp, [rel user_rsp_tmp] |
||||
o64 sysret |
||||
|
||||
user_rsp_tmp: dq 0 |
||||
@ -0,0 +1,62 @@ |
||||
#include "src/syscall.h" |
||||
#include "src/gdt.h" |
||||
#include "src/memory.h" |
||||
#include "src/process.h" |
||||
#include "src/util.h" |
||||
|
||||
#define MSR_EFER 0xC0000080 |
||||
#define MSR_STAR 0xC0000081 |
||||
#define MSR_LSTAR 0xC0000082 |
||||
#define MSR_FMASK 0xC0000084 |
||||
|
||||
static inline uint64_t rdmsr(uint32_t msr) { |
||||
uint32_t lo, hi; |
||||
__asm__ volatile("rdmsr" : "=a"(lo), "=d"(hi) : "c"(msr)); |
||||
return ((uint64_t)hi << 32) | lo; |
||||
} |
||||
|
||||
static inline void wrmsr(uint32_t msr, uint64_t value) { |
||||
__asm__ volatile("wrmsr" : : "c"(msr), "a"((uint32_t)value), "d"((uint32_t)(value >> 32))); |
||||
} |
||||
|
||||
extern void syscall_entry(); |
||||
|
||||
void syscall_init() { |
||||
wrmsr(MSR_EFER, rdmsr(MSR_EFER) | 0x01); |
||||
wrmsr(MSR_STAR, ((uint64_t)KERNEL_DS << 48) | ((uint64_t)KERNEL_CS << 32)); |
||||
wrmsr(MSR_LSTAR, (uint64_t)syscall_entry); |
||||
wrmsr(MSR_FMASK, 0x200); |
||||
} |
||||
|
||||
static void write(uint64_t fd, uint64_t buf, uint64_t size) { |
||||
(void)fd; |
||||
current_process->stdout->write(current_process->stdout, (const char *)buf, size); |
||||
} |
||||
|
||||
static void exit() { |
||||
__asm__ volatile("mov %0, %%cr3" : : "r"(KERNEL_PML4) : "memory"); |
||||
|
||||
|
||||
process_destroy(current_process); |
||||
current_process = NUL; |
||||
|
||||
while (1) |
||||
; |
||||
|
||||
// shutdown for now
|
||||
// outw(0x604, 0x2000);
|
||||
// __asm__ volatile("cli; hlt");
|
||||
} |
||||
|
||||
void syscall_dispatch(uint64_t func, uint64_t arg1, uint64_t arg2, uint64_t arg3) { |
||||
switch (func) { |
||||
case SYSCALL_WRITE: |
||||
write(arg1, arg2, arg3); |
||||
break; |
||||
case SYSCALL_EXIT: |
||||
exit(); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
@ -0,0 +1,10 @@ |
||||
#pragma once |
||||
|
||||
#include <stdint.h> |
||||
|
||||
#define SYSCALL_WRITE 1 |
||||
#define SYSCALL_EXIT 60 |
||||
|
||||
void syscall_init(); |
||||
|
||||
void syscall_dispatch(uint64_t func, uint64_t arg1, uint64_t arg2, uint64_t arg3); |
||||
@ -0,0 +1,9 @@ |
||||
#include "src/tss.h" |
||||
|
||||
tss_t tss = { |
||||
.iopb_offset = sizeof(tss_t) // points past end of TSS = no I/O permissions
|
||||
}; |
||||
|
||||
void tss_set_kernel_stack(void *rsp0) { |
||||
tss.rsp0 = (uint64_t)rsp0; |
||||
} |
||||
@ -0,0 +1,20 @@ |
||||
// tss.h
|
||||
#pragma once |
||||
|
||||
#include <stdint.h> |
||||
|
||||
typedef struct __attribute__((packed)) { |
||||
uint32_t reserved0; |
||||
uint64_t rsp0; |
||||
uint64_t rsp1; |
||||
uint64_t rsp2; |
||||
uint64_t reserved1; |
||||
uint64_t ist[7]; |
||||
uint64_t reserved2; |
||||
uint16_t reserved3; |
||||
uint16_t iopb_offset; |
||||
} tss_t; |
||||
|
||||
extern tss_t tss; |
||||
|
||||
void tss_set_kernel_stack(void *rsp0); |
||||
Loading…
Reference in new issue