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