Add an example user space process

master
Freywar Ulvnaudgari 1 month ago
parent 2d4f76a5dd
commit b32c12b311
  1. 1
      build.sh
  2. 21
      meson.build
  3. 16
      src/app/hello.asm
  4. 4
      src/app/terminal.c
  5. 33
      src/bootloader.asm
  6. 1
      src/fs.h
  7. 68
      src/gdt.c
  8. 12
      src/gdt.h
  9. 35
      src/kernel.c
  10. 2
      src/linker.ld
  11. 72
      src/memory.c
  12. 36
      src/memory.h
  13. 1
      src/path.c
  14. 112
      src/process.c
  15. 16
      src/process.h
  16. 39
      src/string.c
  17. 2
      src/string.h
  18. 39
      src/syscall.asm
  19. 62
      src/syscall.c
  20. 10
      src/syscall.h
  21. 9
      src/tss.c
  22. 20
      src/tss.h
  23. 3
      src/vga.c

@ -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

@ -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

@ -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();

@ -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();

@ -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();
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);
terminal(proc, 0, NUL);
fs_unmount(kp->root);
outw(0x604, 0x2000); // TODO: parse ACPI tables for real hardware
__asm__ volatile("cli; hlt");

@ -1,7 +1,7 @@
ENTRY(kernel_main)
SECTIONS {
. = 0x0000000000020000;
. = 0xFFFFFFFF80020000;
.text : {
*(.text)

@ -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));

@ -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);
}

@ -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));

@ -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;
}

@ -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;

Loading…
Cancel
Save