Add an example user space process
This commit is contained in:
@@ -15,3 +15,4 @@ dd if=build/bootloader.bin of=build/os.img bs="${sector_size}" seek=1 count="$((
|
||||
mkfs.fat -F 16 --offset "${partition_offset}" build/os.img
|
||||
mcopy -i build/os.img@@"$((partition_offset * sector_size))" src ::src
|
||||
mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/kernel.bin ::kernel.bin
|
||||
mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/hello.bin ::hello.bin
|
||||
|
||||
+20
-1
@@ -31,6 +31,14 @@ custom_target(
|
||||
build_by_default: true,
|
||||
)
|
||||
|
||||
custom_target(
|
||||
'hello',
|
||||
input: 'src/app/hello.asm',
|
||||
output: 'hello.bin',
|
||||
command: [nasm, '-f', 'bin', '-l', 'hello.lst', '@INPUT@', '-o', '@OUTPUT@'],
|
||||
build_by_default: true,
|
||||
)
|
||||
|
||||
kernel_entry_o = custom_target(
|
||||
'kernel_entry',
|
||||
input: 'src/kernel_entry.asm',
|
||||
@@ -38,6 +46,12 @@ kernel_entry_o = custom_target(
|
||||
command: [nasm, '-f', 'elf64', '@INPUT@', '-o', '@OUTPUT@'],
|
||||
)
|
||||
|
||||
syscall_o = custom_target('syscall',
|
||||
input: 'src/syscall.asm',
|
||||
output: 'syscall.o',
|
||||
command: [nasm, '-f', 'elf64', '@INPUT@', '-o', '@OUTPUT@'],
|
||||
)
|
||||
|
||||
cc = meson.get_compiler('c')
|
||||
|
||||
kernel_sources = files(
|
||||
@@ -47,6 +61,7 @@ kernel_sources = files(
|
||||
'src/ata.c',
|
||||
'src/fat16.c',
|
||||
'src/fs.c',
|
||||
'src/gdt.c',
|
||||
'src/idt.c',
|
||||
'src/kernel.c',
|
||||
'src/keyboard.c',
|
||||
@@ -54,19 +69,23 @@ kernel_sources = files(
|
||||
'src/panic.c',
|
||||
'src/path.c',
|
||||
'src/pic.c',
|
||||
'src/process.c',
|
||||
'src/string.c',
|
||||
'src/syscall.c',
|
||||
'src/tss.c',
|
||||
'src/vga.c',
|
||||
)
|
||||
|
||||
kernel_elf = executable(
|
||||
'kernel.elf',
|
||||
sources: [kernel_entry_o, kernel_sources],
|
||||
sources: [kernel_entry_o, syscall_o, kernel_sources],
|
||||
c_args: [
|
||||
'-ffreestanding',
|
||||
'-nostdlib',
|
||||
'-nostartfiles',
|
||||
'-mno-red-zone',
|
||||
'-mgeneral-regs-only',
|
||||
'-mcmodel=kernel',
|
||||
'-Wno-unused-command-line-argument',
|
||||
'-Wconversion',
|
||||
'-DVERSION="' + meson.project_version() + '"',
|
||||
|
||||
@@ -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
|
||||
+1
-3
@@ -270,9 +270,7 @@ void terminal(process_t *p, __attribute__((unused)) uint8_t argc, __attribute__(
|
||||
|
||||
proc = p;
|
||||
|
||||
char *greeting = string_format("Welcome to FreywarOS v%s!\n\n", VERSION);
|
||||
WRITE_D(greeting);
|
||||
memory_free(greeting);
|
||||
WRITE_D("Welcome to FreywarOS v" VERSION "!\n\n");
|
||||
|
||||
print_prompt();
|
||||
|
||||
|
||||
+20
-13
@@ -224,30 +224,30 @@ jmp load_gdt
|
||||
|
||||
gdt_start:
|
||||
gdt_0: dq 0x0000000000000000
|
||||
gdt_1:
|
||||
gdt_32_code:
|
||||
.limit_low: dw 0xFFFF
|
||||
.base_low: dw 0x0000
|
||||
.base_middle: db 0x00
|
||||
.access: db 10011010b ; present, ring 0, code, executable, readable
|
||||
.flags: db 11001111b ; 32-bit, 4KB granularity
|
||||
.base_high: db 0x00
|
||||
gdt_1_end:
|
||||
gdt_2:
|
||||
gdt_32_code_end:
|
||||
gdt_64_code:
|
||||
.limit_low: dw 0xFFFF
|
||||
.base_low: dw 0x0000
|
||||
.base_middle: db 0x00
|
||||
.access: db 10011010b ; present, ring 0, code, executable, readable
|
||||
.flags: db 10101111b ; long mode (L bit)
|
||||
.base_high: db 0x00
|
||||
gdt_2_end:
|
||||
gdt_3:
|
||||
gdt_64_code_end:
|
||||
gdt_data:
|
||||
.limit_low: dw 0xFFFF
|
||||
.base_low: dw 0x0000
|
||||
.base_middle: db 0x00
|
||||
.access: db 10010010b ; present, ring 0, data, writable
|
||||
.flags: db 00000000b
|
||||
.base_high: db 0x00
|
||||
gdt_3_end:
|
||||
gdt_data_end:
|
||||
gdt_end:
|
||||
|
||||
gdt_descriptor:
|
||||
@@ -276,23 +276,30 @@ protected_mode:
|
||||
mov ss, ax
|
||||
mov esp, 0x00090000
|
||||
|
||||
; zero page table memory at 0x00010000 (3 pages = 768 dwords)
|
||||
; zero page table memory
|
||||
mov edi, 0x00010000
|
||||
mov ecx, 768
|
||||
mov ecx, 256 * 5
|
||||
xor eax, eax
|
||||
rep stosd
|
||||
|
||||
; PML4[0] -> PDPT at 0x00011000
|
||||
mov dword [0x00010000], 0x00011003
|
||||
; PDPT[0] -> PD at 0x00012000
|
||||
mov dword [0x00011000], 0x00012003
|
||||
; PML4[511] -> PDPT at 0x00012000
|
||||
mov dword [0x00010FF8], 0x00012003
|
||||
; PML4[0].PDPT[0] -> PD at 0x00013000
|
||||
mov dword [0x00011000], 0x00013003
|
||||
; PML4[511].PDPT[510] -> PD at 0x00014000
|
||||
mov dword [0x00012FF0], 0x00014003
|
||||
; PD: fill 64 entries, each mapping 2MB
|
||||
mov edi, 0x00012000
|
||||
mov edi, 0x00013000
|
||||
mov eax, 0x00000083 ; present, writable, huge page, base 0
|
||||
mov ecx, 64
|
||||
|
||||
.fill_pd:
|
||||
mov ebx, edi
|
||||
add ebx, 0x1000
|
||||
mov dword [edi], eax
|
||||
mov dword [ebx], eax
|
||||
add edi, 8
|
||||
add eax, 0x00200000 ; next 2MB
|
||||
loop .fill_pd
|
||||
@@ -327,11 +334,11 @@ long_mode:
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov ss, ax
|
||||
mov rsp, 0x0000000000090000
|
||||
mov rsp, 0xFFFFFFFF80090000
|
||||
|
||||
xor rax, rax
|
||||
xor rbx, rbx
|
||||
xor rcx, rcx
|
||||
xor rdx, rdx
|
||||
|
||||
jmp 0x00020000
|
||||
jmp 0xFFFFFFFF80020000
|
||||
|
||||
@@ -11,7 +11,6 @@ typedef struct fs_node {
|
||||
uint8_t type;
|
||||
} fs_node_t;
|
||||
|
||||
|
||||
fs_node_t *fs_mount();
|
||||
|
||||
fs_node_t *fs_open_by(const fs_node_t *directory, const char *name);
|
||||
|
||||
@@ -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();
|
||||
+28
-7
@@ -1,11 +1,13 @@
|
||||
#include "src/app/terminal.h"
|
||||
#include "src/fs.h"
|
||||
#include "src/gdt.h"
|
||||
#include "src/idt.h"
|
||||
#include "src/keyboard.h"
|
||||
#include "src/memory.h"
|
||||
#include "src/panic.h"
|
||||
#include "src/path.h"
|
||||
#include "src/pic.h"
|
||||
#include "src/process.h"
|
||||
#include "src/syscall.h"
|
||||
#include "src/util.h"
|
||||
#include "src/vga.h"
|
||||
|
||||
@@ -42,15 +44,34 @@ void kernel_main() {
|
||||
idt_set_entry(46, isr_ata_primary, 0x8E);
|
||||
__asm__ volatile("sti");
|
||||
|
||||
gdt_init();
|
||||
syscall_init();
|
||||
|
||||
memory_init();
|
||||
|
||||
process_t *proc = memory_allocate(sizeof(process_t));
|
||||
proc->cwd = memory_allocate(sizeof(path_t));
|
||||
proc->root = fs_mount();
|
||||
proc->stdin = keyboard_init();
|
||||
proc->stdout = vga_init();
|
||||
process_t *kp = memory_allocate(sizeof(process_t));
|
||||
kp->root = fs_mount();
|
||||
kp->cwd = memory_allocate(sizeof(path_t));
|
||||
kp->stdin = keyboard_init();
|
||||
kp->stdout = vga_init();
|
||||
|
||||
terminal(proc, 0, NUL);
|
||||
fs_node_t *hello = fs_open_by(kp->root, "HELLO.BIN");
|
||||
|
||||
ASSERT(hello, "kernel: hello.bin not found");
|
||||
|
||||
uint8_t *hello_code = memory_allocate(hello->size);
|
||||
fs_read(hello, 0, hello->size, hello_code);
|
||||
|
||||
process_t *proc = process_create(kp, hello_code, hello->size);
|
||||
|
||||
memory_free(hello_code);
|
||||
fs_close(hello);
|
||||
|
||||
process_run(proc);
|
||||
|
||||
while (1);
|
||||
|
||||
fs_unmount(kp->root);
|
||||
|
||||
outw(0x604, 0x2000); // TODO: parse ACPI tables for real hardware
|
||||
__asm__ volatile("cli; hlt");
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
ENTRY(kernel_main)
|
||||
|
||||
SECTIONS {
|
||||
. = 0x0000000000020000;
|
||||
. = 0xFFFFFFFF80020000;
|
||||
|
||||
.text : {
|
||||
*(.text)
|
||||
|
||||
+63
-9
@@ -1,11 +1,7 @@
|
||||
#include "src/memory.h"
|
||||
#include "src/panic.h"
|
||||
#include "src/util.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#define MEMORY_SIZE 134217728
|
||||
#define PAGE_SIZE 4096
|
||||
#define PAGE_COUNT (MEMORY_SIZE / PAGE_SIZE)
|
||||
#define MAP_UNIT 64
|
||||
#define FULL_UNIT 0xFFFFFFFFFFFFFFFF
|
||||
|
||||
@@ -26,7 +22,7 @@ static void set_allocated(uint16_t page, uint8_t allocated) {
|
||||
}
|
||||
}
|
||||
|
||||
static void *memory_page_allocate() {
|
||||
void *memory_page_allocate() {
|
||||
ASSERT(free_page < PAGE_COUNT, "memory_page_allocate: out of memory");
|
||||
const uint16_t page = free_page;
|
||||
set_allocated(page, 1);
|
||||
@@ -40,7 +36,7 @@ static void *memory_page_allocate() {
|
||||
return (void *)((uint64_t)page * PAGE_SIZE);
|
||||
}
|
||||
|
||||
__attribute__((unused)) static void memory_page_free(void *address) {
|
||||
void memory_page_free(void *address) {
|
||||
uint16_t page = (uint16_t)((uint64_t)address / PAGE_SIZE);
|
||||
ASSERT(get_allocated(page), "memory_page_free: page not allocated")
|
||||
set_allocated(page, 0);
|
||||
@@ -49,7 +45,65 @@ __attribute__((unused)) static void memory_page_free(void *address) {
|
||||
}
|
||||
}
|
||||
|
||||
#define HEAP_PAGE_COUNT 256
|
||||
void memory_page_map(uint64_t *pml4, void *virt, void *phys, uint64_t flags) {
|
||||
const uint64_t ivirt = (uint64_t)virt;
|
||||
const uint64_t pml4_index = (ivirt >> 39) & 0x1FF;
|
||||
const uint64_t pdpt_index = (ivirt >> 30) & 0x1FF;
|
||||
const uint64_t pd_index = (ivirt >> 21) & 0x1FF;
|
||||
const uint64_t pt_index = (ivirt >> 12) & 0x1FF;
|
||||
|
||||
if (!(pml4[pml4_index] & PAGE_PRESENT)) {
|
||||
uint64_t *pdpt = memory_page_allocate();
|
||||
memory_set(0, PAGE_SIZE, PHYS_TO_VIRT(pdpt));
|
||||
pml4[pml4_index] = (uint64_t)pdpt | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
|
||||
}
|
||||
|
||||
uint64_t *pdpt = PHYS_TO_VIRT(pml4[pml4_index] & ~(uint64_t)0xFFF);
|
||||
if (!(pdpt[pdpt_index] & PAGE_PRESENT)) {
|
||||
uint64_t *pd = memory_page_allocate();
|
||||
memory_set(0, PAGE_SIZE, PHYS_TO_VIRT(pd));
|
||||
pdpt[pdpt_index] = (uint64_t)pd | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
|
||||
}
|
||||
|
||||
uint64_t *pd = PHYS_TO_VIRT(pdpt[pdpt_index] & ~(uint64_t)0xFFF);
|
||||
ASSERT(!(pd[pd_index] & 0x80), "memory_page_map: huge page in PD");
|
||||
if (!(pd[pd_index] & PAGE_PRESENT)) {
|
||||
uint64_t *pt = memory_page_allocate();
|
||||
memory_set(0, PAGE_SIZE, PHYS_TO_VIRT(pt));
|
||||
pd[pd_index] = (uint64_t)pt | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
|
||||
}
|
||||
|
||||
uint64_t *pt = PHYS_TO_VIRT(pd[pd_index] & ~(uint64_t)0xFFF);
|
||||
pt[pt_index] = (uint64_t)phys | flags | PAGE_PRESENT;
|
||||
}
|
||||
|
||||
void memory_page_unmap(uint64_t *pml4, void *virt) {
|
||||
const uint64_t ivirt = (uint64_t)virt;
|
||||
const uint64_t pml4_index = (ivirt >> 39) & 0x1FF;
|
||||
const uint64_t pdpt_index = (ivirt >> 30) & 0x1FF;
|
||||
const uint64_t pd_index = (ivirt >> 21) & 0x1FF;
|
||||
const uint64_t pt_index = (ivirt >> 12) & 0x1FF;
|
||||
|
||||
if (!(pml4[pml4_index] & PAGE_PRESENT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t *pdpt = PHYS_TO_VIRT(pml4[pml4_index] & ~(uint64_t)0xFFF);
|
||||
if (!(pdpt[pdpt_index] & PAGE_PRESENT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t *pd = PHYS_TO_VIRT(pdpt[pdpt_index] & ~(uint64_t)0xFFF);
|
||||
if (!(pd[pd_index] & PAGE_PRESENT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t *pt = PHYS_TO_VIRT(pd[pd_index] & ~(uint64_t)0xFFF);
|
||||
memory_page_free((void *)(pt[pt_index] & ~(uint64_t)0xFFF));
|
||||
pt[pt_index] = 0;
|
||||
|
||||
__asm__ volatile("invlpg (%0)" : : "r"(virt) : "memory");
|
||||
}
|
||||
|
||||
typedef struct free_chunk {
|
||||
uint64_t size; // header + data
|
||||
@@ -59,9 +113,9 @@ typedef struct free_chunk {
|
||||
static free_chunk_t *free_list;
|
||||
|
||||
void memory_init() {
|
||||
free_list = memory_page_allocate();
|
||||
free_list = PHYS_TO_VIRT(memory_page_allocate());
|
||||
for (uint64_t i = 1; i < HEAP_PAGE_COUNT; i++) {
|
||||
memory_page_allocate(); // TODO Map the pages.
|
||||
memory_page_allocate();
|
||||
}
|
||||
free_list->size = HEAP_PAGE_COUNT * PAGE_SIZE;
|
||||
free_list->next = NUL;
|
||||
|
||||
@@ -3,8 +3,44 @@
|
||||
#include "src/panic.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#define PAGE_PRESENT 0x01
|
||||
#define PAGE_WRITABLE 0x02
|
||||
#define PAGE_USER 0x04
|
||||
#define PAGE_PWT 0x08
|
||||
#define PAGE_PCD 0x10
|
||||
#define PAGE_ACCESSED 0x20
|
||||
#define PAGE_DIRTY 0x40
|
||||
#define PAGE_HUGE 0x80
|
||||
#define PAGE_GLOBAL 0x100
|
||||
#define PAGE_NX (1ULL << 63)
|
||||
|
||||
#define MEMORY_SIZE 0x08000000
|
||||
#define PAGE_SIZE 4096
|
||||
#define PAGE_COUNT (MEMORY_SIZE / PAGE_SIZE)
|
||||
|
||||
#define HEAP_PAGE_COUNT 256
|
||||
|
||||
#define KERNEL_VIRTUAL_BASE 0xFFFFFFFF80000000ULL
|
||||
#define PHYS_TO_VIRT(phys) ((void *)((uint64_t)(phys) + KERNEL_VIRTUAL_BASE))
|
||||
#define VIRT_TO_PHYS(virt) ((uint64_t)(virt) - KERNEL_VIRTUAL_BASE)
|
||||
|
||||
#define KERNEL_PML4 0xFFFFFFFF80010000ULL
|
||||
|
||||
#define USER_VIRTUAL_BASE 0x0000000000000000ULL
|
||||
#define USER_VIRTUAL_CODE (USER_VIRTUAL_BASE + 0x400000)
|
||||
#define USER_VIRTUAL_HEAP (USER_VIRTUAL_CODE + 0x400000)
|
||||
#define USER_VIRTUAL_STACK (0x0000700000000000ULL - PAGE_SIZE)
|
||||
|
||||
void memory_init();
|
||||
|
||||
void *memory_page_allocate();
|
||||
|
||||
void memory_page_free(void *page);
|
||||
|
||||
void memory_page_map(uint64_t *pml4, void *virt, void *phys, uint64_t flags);
|
||||
|
||||
void memory_page_unmap(uint64_t *pml4, void *virt);
|
||||
|
||||
void *memory_allocate(uint64_t size);
|
||||
|
||||
void memory_free(void *pointer);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "src/memory.h"
|
||||
#include "src/string.h"
|
||||
#include "src/util.h"
|
||||
#include <stdint.h>
|
||||
|
||||
path_t *path_open(const fs_node_t *root, const path_t *source, char *path) {
|
||||
path_t *result = memory_allocate(sizeof(path_t));
|
||||
|
||||
+112
@@ -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);
|
||||
}
|
||||
+14
-2
@@ -5,14 +5,26 @@
|
||||
#include "src/stream.h"
|
||||
#include "src/string.h"
|
||||
|
||||
typedef struct {
|
||||
path_t *cwd;
|
||||
#define USER_RFLAGS 0x202
|
||||
|
||||
typedef struct process {
|
||||
uint64_t *pml4;
|
||||
void *kernel_stack;
|
||||
fs_node_t *root;
|
||||
path_t *cwd;
|
||||
stream_t *stdin;
|
||||
stream_t *stdout;
|
||||
} process_t;
|
||||
|
||||
typedef void (*app_t)(process_t *proc, uint8_t argc, char **argv);
|
||||
|
||||
extern process_t *current_process;
|
||||
|
||||
process_t *process_create(const process_t *parent, const uint8_t *code, uint64_t size);
|
||||
|
||||
void process_run(process_t *proc);
|
||||
|
||||
void process_destroy(process_t *proc);
|
||||
|
||||
#define WRITE_S(s) proc->stdout->write(proc->stdout, s, sizeof(s) - 1);
|
||||
#define WRITE_D(s) proc->stdout->write(proc->stdout, s, string_length(s));
|
||||
|
||||
+18
-21
@@ -1,7 +1,5 @@
|
||||
#include "src/string.h"
|
||||
#include "src/memory.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
|
||||
uint8_t bytes_equal(const char *l, const char *r, uint64_t count) {
|
||||
while (count--) {
|
||||
@@ -164,41 +162,39 @@ uint64_t string_uint_to_hex(uint64_t value, uint64_t max, char *result) {
|
||||
return i;
|
||||
}
|
||||
|
||||
char *string_format(const char *format, ...) {
|
||||
uint64_t string_format(const char *format, uint64_t max, char *output, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
va_start(args, output);
|
||||
|
||||
uint64_t limit = 1023;
|
||||
|
||||
char *result = memory_allocate(limit + 1);
|
||||
uint64_t limit = max - 1;
|
||||
|
||||
uint64_t fi = 0, ri = 0;
|
||||
while (format[fi] && ri < limit) {
|
||||
if (format[fi] != '%') {
|
||||
result[ri++] = format[fi++];
|
||||
output[ri++] = format[fi++];
|
||||
} else {
|
||||
switch (format[fi + 1]) {
|
||||
case 'c':
|
||||
result[ri++] = (char)va_arg(args, int);
|
||||
output[ri++] = (char)va_arg(args, int);
|
||||
fi += 2;
|
||||
break;
|
||||
case 'd':
|
||||
string_int_to_decimal(va_arg(args, int64_t), limit - ri, result + ri);
|
||||
while (result[ri]) {
|
||||
string_int_to_decimal(va_arg(args, int64_t), limit - ri, output + ri);
|
||||
while (output[ri]) {
|
||||
ri++;
|
||||
}
|
||||
fi += 2;
|
||||
break;
|
||||
case 'u':
|
||||
string_uint_to_decimal(va_arg(args, uint64_t), limit - ri, result + ri);
|
||||
while (result[ri]) {
|
||||
string_uint_to_decimal(va_arg(args, uint64_t), limit - ri, output + ri);
|
||||
while (output[ri]) {
|
||||
ri++;
|
||||
}
|
||||
fi += 2;
|
||||
break;
|
||||
case 'x':
|
||||
string_uint_to_hex(va_arg(args, uint64_t), limit - ri, result + ri);
|
||||
while (result[ri]) {
|
||||
string_uint_to_hex(va_arg(args, uint64_t), limit - ri, output + ri);
|
||||
while (output[ri]) {
|
||||
ri++;
|
||||
}
|
||||
fi += 2;
|
||||
@@ -206,25 +202,26 @@ char *string_format(const char *format, ...) {
|
||||
case 's': {
|
||||
char *s = va_arg(args, char *);
|
||||
while (*s && ri < limit) {
|
||||
result[ri++] = *s;
|
||||
output[ri++] = *s;
|
||||
s++;
|
||||
}
|
||||
fi += 2;
|
||||
break;
|
||||
}
|
||||
case '%': {
|
||||
result[ri++] = '%';
|
||||
output[ri++] = '%';
|
||||
fi += 2;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
result[ri++] = format[fi++];
|
||||
result[ri++] = format[fi++];
|
||||
output[ri++] = format[fi++];
|
||||
output[ri++] = format[fi++];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
result[ri] = '\0';
|
||||
output[ri] = '\0';
|
||||
va_end(args);
|
||||
return result;
|
||||
|
||||
return ri;
|
||||
}
|
||||
|
||||
+1
-1
@@ -20,4 +20,4 @@ uint64_t string_int_to_decimal(int64_t value, uint64_t max, char *result);
|
||||
|
||||
uint64_t string_uint_to_hex(uint64_t value, uint64_t max, char *result);
|
||||
|
||||
char *string_format(const char *format, ...);
|
||||
uint64_t string_format(const char *format, uint64_t max, char *output, ...);
|
||||
|
||||
@@ -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);
|
||||
@@ -1,9 +1,8 @@
|
||||
#include "src/vga.h"
|
||||
#include "src/memory.h"
|
||||
#include "src/util.h"
|
||||
#include <stdint.h>
|
||||
|
||||
static uint16_t *vga = (uint16_t *)0x000B8000;
|
||||
static uint16_t *vga = (uint16_t *)0xFFFFFFFF800B8000;
|
||||
static uint16_t color = (uint16_t)0x0F << 8;
|
||||
static uint16_t offset = 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user