summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorBenji Dial <benji@benjidial.net>2024-01-13 16:43:49 -0500
committerBenji Dial <benji@benjidial.net>2024-01-13 16:43:49 -0500
commit4130562b1555cabe441efe9420cebe12e7ed8d39 (patch)
treebeaf0012373aab2c3a13fe0147a5cda4af28ef78 /kernel
parent882e74b2191c059a9226cbd8bcb51c97da36247c (diff)
downloadhilbert-os-4130562b1555cabe441efe9420cebe12e7ed8d39.tar.gz
application loading
Diffstat (limited to 'kernel')
-rw-r--r--kernel/application.cpp266
-rw-r--r--kernel/entry.cpp140
-rw-r--r--kernel/paging.cpp72
-rw-r--r--kernel/syscall.asm160
-rw-r--r--kernel/syscall.cpp46
-rw-r--r--kernel/terminal.cpp10
-rw-r--r--kernel/vfile.cpp7
7 files changed, 601 insertions, 100 deletions
diff --git a/kernel/application.cpp b/kernel/application.cpp
new file mode 100644
index 0000000..19b1dbc
--- /dev/null
+++ b/kernel/application.cpp
@@ -0,0 +1,266 @@
+#include <mercury/kernel/application.hpp>
+#include <mercury/kernel/paging.hpp>
+
+//TODO - scheduling.
+
+namespace mercury::kernel::application {
+
+ app_instance::app_instance() : state(app_state::paused) {
+
+ framebuffer_vaddr = 0;
+
+ uint64_t p3_paddr;
+ uint64_t p2_paddr;
+
+ uint64_t p4_vaddr;
+ uint64_t p3_vaddr;
+ uint64_t p2_vaddr;
+
+ paging::map_new_kernel_page(p4_vaddr, p4_paddr);
+ paging::map_new_kernel_page(p3_vaddr, p3_paddr);
+ paging::map_new_kernel_page(p2_vaddr, p2_paddr);
+
+ p4 = (uint64_t *)p4_vaddr;
+ p3 = (uint64_t *)p3_vaddr;
+ p2 = (uint64_t *)p2_vaddr;
+
+ for (int i = 1; i < 511; ++i)
+ p4[i] = 0;
+ p4[511] = paging::kernel_p4e;
+ p4[0] = paging::encode_pte(p3_paddr, true, true, true, false);
+
+ for (int i = 1; i < 512; ++i)
+ p3[i] = 0;
+ p3[0] = paging::encode_pte(p2_paddr, true, true, true, false);
+
+ for (int i = 0; i < 512; ++i)
+ p2[i] = 0;
+
+ p2es_to_free_on_exit = new bool[512];
+
+ }
+
+ app_instance::~app_instance() {
+
+ for (int i = 1; i < 512; ++i)
+ if (p2[i] != 0 && p2es_to_free_on_exit[i]) {
+ uint64_t paddr = p2[i] & ~0x1fffffULL;
+ paging::mark_pram_region_free(paddr, paddr + 0x200000);
+ }
+
+ delete[] p2es_to_free_on_exit;
+
+ uint64_t p2_paddr = p3[0] & ~0x1fffffULL;
+ paging::unmap_kernel_page((uint64_t)p2);
+ paging::mark_pram_region_free(p2_paddr, p2_paddr + 4096);
+
+ uint64_t p3_paddr = p4[0] & ~0x1fffffULL;
+ paging::unmap_kernel_page((uint64_t)p3);
+ paging::mark_pram_region_free(p3_paddr, p3_paddr + 4096);
+
+ paging::unmap_kernel_page((uint64_t)p4);
+ paging::mark_pram_region_free(p4_paddr, p4_paddr + 4096);
+
+ }
+
+ void app_instance::map_page(uint64_t vaddr, uint64_t paddr,
+ bool write, bool execute, bool free_pram_on_exit
+ ) {
+ uint64_t i = vaddr / 0x200000;
+ p2[i] = paging::encode_pte(paddr, true, write, execute, true);
+ p2es_to_free_on_exit[i] = free_pram_on_exit;
+ }
+
+ uint64_t app_instance::get_free_vaddr_pages(uint64_t count) {
+ uint64_t start = 1;
+ uint64_t length = 0;
+ while (start + length < 510) {
+ if (length == count)
+ return start * 0x200000;
+ if (p2[start + length] == 0)
+ ++length;
+ else {
+ start += length + 1;
+ length = 0;
+ }
+ }
+ //TODO: handle out of memory
+ return 0;
+ }
+
+ void app_instance::create_stack() {
+ uint64_t stack_paddr = paging::take_2mib_pram_page();
+ map_page(0x3fe00000, stack_paddr, true, false, true);
+ for (int i = 0; i < 512; ++i) {
+ uint64_t vaddr = paging::find_unmapped_vram_region(1);
+ paging::map_kernel_page(stack_paddr + 512 * i, vaddr, true, false);
+ for (int j = 0; j < 4096 / 8; ++j)
+ *(uint64_t *)(vaddr + j * 8) = 0;
+ paging::unmap_kernel_page(vaddr);
+ }
+ saved_regs.rsp = 0x40000000;
+ }
+
+ void app_instance::set_instruction_pointer(uint64_t vaddr) {
+ saved_regs.rip = vaddr;
+ }
+
+ uint64_t app_instance::count_mapped_vram_pages() {
+ uint64_t count = 0;
+ for (int i = 1; i < 512; ++i)
+ if (p2[i] != 0)
+ ++count;
+ return count;
+ }
+
+ app_instance *running_app;
+
+ static uint8_t correct_magic[16] = {
+ 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00,
+ 0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00
+ };
+
+#define READ(a, b, c) \
+ { \
+ storage::fs_result _result = file.read_file(a, b, c); \
+ if (_result == storage::fs_result::device_error) \
+ return create_app_result::device_error; \
+ if (_result == storage::fs_result::fs_corrupt) \
+ return create_app_result::fs_corrupt; \
+ }
+
+ struct load_info {
+ uint64_t foffset;
+ uint64_t fsize;
+ uint64_t vaddr;
+ uint64_t vpages;
+ bool writable;
+ bool executable;
+ };
+
+ create_app_result create_app(const vfile::vfile &file, app_instance *&out) {
+
+ uint8_t magic[16];
+ if (file.dir_entry.length < 64)
+ return create_app_result::app_corrupt;
+ READ(0, 8, magic)
+ READ(16, 8, magic + 8)
+ for (int i = 0; i < 16; ++i)
+ if (magic[i] != correct_magic[i])
+ return create_app_result::app_corrupt;
+
+ uint64_t entry_point;
+ uint64_t phead_start;
+ uint16_t phead_entry_size;
+ uint16_t phead_entry_count;
+
+ READ(24, 8, &entry_point)
+ READ(32, 8, &phead_start)
+ READ(54, 2, &phead_entry_size)
+ READ(56, 2, &phead_entry_count)
+
+ if (file.dir_entry.length <
+ phead_start + phead_entry_size * phead_entry_count)
+ return create_app_result::app_corrupt;
+
+ utility::vector<load_info> load_infos;
+
+ for (uint16_t i = 0; i < phead_entry_count; ++i) {
+
+ uint64_t entry_start = phead_start + phead_entry_size * i;
+
+ uint32_t seg_type;
+ READ(entry_start, 4, &seg_type)
+ if (seg_type != 1)
+ continue;
+
+ uint64_t foffset;
+ uint64_t vaddr;
+ uint64_t fsize;
+ uint64_t vsize;
+ uint32_t flags;
+
+ READ(entry_start + 8, 8, &foffset)
+ READ(entry_start + 16, 8, &vaddr)
+ READ(entry_start + 32, 8, &fsize)
+ READ(entry_start + 40, 8, &vsize)
+ READ(entry_start + 4, 4, &flags)
+
+ if (vaddr & 0x1fffff)
+ return create_app_result::app_corrupt;
+ if (file.dir_entry.length < foffset + fsize)
+ return create_app_result::app_corrupt;
+ if (fsize > vsize)
+ return create_app_result::app_corrupt;
+ if (vaddr == 0)
+ return create_app_result::app_corrupt;
+
+ uint64_t vpages = (vsize - 1) / 0x200000 + 1;
+
+ if (vaddr + vpages * 0x200000 > ((1 << 30) - (4 << 20)))
+ return create_app_result::app_corrupt;
+
+ load_info info = {
+ .foffset = foffset,
+ .fsize = fsize,
+ .vaddr = vaddr,
+ .vpages = vpages,
+ .writable = (flags & 2) == 2,
+ .executable = (flags & 1) == 1
+ };
+ load_infos.add_end(info);
+
+ }
+
+ out = new app_instance();
+
+ for (unsigned i = 0; i < load_infos.count; ++i) {
+ const auto &info = load_infos.buffer[i];
+ for (uint64_t j = 0; j < info.vpages; ++j) {
+ uint64_t paddr = paging::take_2mib_pram_page();
+ out->map_page(info.vaddr + j * 0x200000, paddr,
+ info.writable, info.executable, true);
+ for (int k = 0; k < 512; ++k) {
+ uint64_t offset_in_segment = j * 0x200000 + k * 4096;
+ uint64_t kvaddr = paging::find_unmapped_vram_region(1);
+ paging::map_kernel_page(paddr + k * 4096, kvaddr, true, false);
+ storage::fs_result result = storage::fs_result::success;
+ if (info.fsize > offset_in_segment) {
+ if (info.fsize >= offset_in_segment + 4096)
+ result = file.read_file(
+ info.foffset + offset_in_segment, 4096, (void *)kvaddr);
+ else {
+ int to_read = info.fsize - offset_in_segment;
+ result = file.read_file(
+ info.foffset + offset_in_segment, to_read, (void *)kvaddr);
+ uint8_t *blank = (uint8_t *)(kvaddr + to_read);
+ for (int i = 0; i < 4096 - to_read; ++i)
+ blank[i] = 0;
+ }
+ }
+ else {
+ uint8_t *blank = (uint8_t *)kvaddr;
+ for (int i = 0; i < 4096; ++i)
+ blank[i] = 0;
+ }
+ paging::unmap_kernel_page(kvaddr);
+ if (result == storage::fs_result::device_error) {
+ delete out;
+ return create_app_result::device_error;
+ }
+ if (result == storage::fs_result::fs_corrupt) {
+ delete out;
+ return create_app_result::fs_corrupt;
+ }
+ }
+ }
+ }
+
+ out->create_stack();
+ out->set_instruction_pointer(entry_point);
+
+ return create_app_result::success;
+
+ }
+
+}
diff --git a/kernel/entry.cpp b/kernel/entry.cpp
index 445d560..f7ba71d 100644
--- a/kernel/entry.cpp
+++ b/kernel/entry.cpp
@@ -1,5 +1,6 @@
#include <mercury/kernel/storage/bd/memory.hpp>
#include <mercury/kernel/storage/fs/tarfs.hpp>
+#include <mercury/kernel/application.hpp>
#include <mercury/kernel/framebuffer.hpp>
#include <mercury/kernel/terminal.hpp>
#include <mercury/kernel/limine.hpp>
@@ -103,6 +104,8 @@ uint64_t initfs_len;
[[noreturn]] static void with_kernel_p4();
+extern "C" void load_gdt_and_idt();
+
extern "C" [[noreturn]] void entry() {
//TODO?: maybe we should check if the limine requests were
@@ -113,9 +116,9 @@ extern "C" [[noreturn]] void entry() {
paging::mark_all_pram_used();
auto memmap = memmap_request.response;
for (uint64_t i = 0; i < memmap->entry_count; ++i) {
- //we don't start allocating physical pages until after we are done using
- //limine structures (specifically at the call to paging::map_kernel_stack),
- //so we consider bootloader reclaimable to be free. usable and bootloader
+ //we don't allocate any physical pages until after we are done using limine
+ //structures (specifically at the call to paging::map_kernel_stacks), so
+ //we consider bootloader reclaimable to be free. usable and bootloader
//reclaimable are guaranteed by limine spec to be page-aligned.
auto entry = memmap->entries[i];
if (entry->type == LIMINE_MEMMAP_USABLE ||
@@ -175,79 +178,29 @@ extern "C" [[noreturn]] void entry() {
//switch to kernel p4
- paging::map_kernel_stack();
+ paging::map_kernel_stacks();
+ load_gdt_and_idt();
switch_to_kernel_p4(&with_kernel_p4);
}
+static void print_mem() {
+ uint64_t used_vram_mib = (paging::get_used_vram_page_count() + 128) / 256;
+ uint64_t free_pram_mib = (paging::get_free_pram_page_count() + 128) / 256;
+ terminal::put_int_decimal(used_vram_mib);
+ terminal::put_string_sz(" MiB kernel memory mapped.\n");
+ terminal::put_int_decimal(free_pram_mib);
+ terminal::put_string_sz(" MiB physical memory free.\n");
+}
+
[[noreturn]] static void print_and_halt(const char *msg) {
terminal::put_string_sz(msg);
while (1)
asm ("hlt");
}
-static void draw_indent(unsigned indent) {
- for (unsigned i = 0; i < indent; ++i)
- terminal::put_char(' ');
-}
-
-static void dir_tree(
- const vfile::vfile &root, const vfile::vfile &f, unsigned indent
-) {
-
- draw_indent(indent);
- terminal::put_string(f.dir_entry.name);
- terminal::put_char('\n');
-
- std::optional<vfile::vfile> followed;
- utility::vector<vfile::vfile> children;
-
- switch (f.dir_entry.type) {
-
- case storage::file_type::regular_file:
- draw_indent(indent + 2);
- terminal::put_string_sz("type: regular file\n");
- draw_indent(indent + 2);
- terminal::put_string_sz("length: ");
- terminal::put_int_decimal(f.dir_entry.length);
- terminal::put_string_sz(" bytes\n");
- break;
-
- case storage::file_type::symlink:
- draw_indent(indent + 2);
- terminal::put_string_sz("type: symlink\n");
- draw_indent(indent + 2);
- terminal::put_string_sz("target: ");
- terminal::put_string(f.dir_entry.target);
- terminal::put_char('\n');
- if (f.follow_symlinks(root, followed) != storage::fs_result::success)
- print_and_halt("failed to follow symlink.");
- if (!followed) {
- draw_indent(indent + 4);
- terminal::put_string_sz("[broken]\n");
- }
- dir_tree(root, *followed, indent + 4);
- break;
-
- case storage::file_type::directory:
- if (f.get_children(children) != storage::fs_result::success)
- print_and_halt("failed to get children.");
- draw_indent(indent + 2);
- terminal::put_string_sz("type: directory\n");
- draw_indent(indent + 2);
- terminal::put_string_sz("children:\n");
- if (children.count == 0) {
- draw_indent(indent + 4);
- terminal::put_string_sz("[empty]\n");
- }
- else
- for (unsigned i = 0; i < children.count; ++i)
- dir_tree(root, children.buffer[i], indent + 4);
- break;
-
- }
-
-}
+extern "C" [[noreturn]] void start_user_mode(
+ uint64_t rip, uint64_t rsp, uint64_t p4_paddr);
[[noreturn]] static void with_kernel_p4() {
@@ -257,27 +210,46 @@ static void dir_tree(
storage::fs::tarfs_instance initfs_fs(&initfs_bd);
initfs_bd.mounted_as = &initfs_fs;
- terminal::put_string_sz("kernel initialization complete.\n");
-
- int used_vram_kib = paging::get_used_vram_page_count() * 4;
- int free_pram_kib = paging::get_free_pram_page_count() * 4;
+ vfile::vfile vfs_root;
+ vfs_root.bd = &initfs_bd;
+ vfs_root.dir_entry.type = storage::file_type::directory;
+ vfs_root.path.absolute = true;
- terminal::put_int_decimal(used_vram_kib);
- terminal::put_string_sz(" kiB kernel memory mapped.\n");
- terminal::put_int_decimal(free_pram_kib);
- terminal::put_string_sz(" kiB physical memory free.\n");
+ if (initfs_fs.get_root_node(vfs_root.dir_entry.node) !=
+ storage::fs_result::success)
+ print_and_halt("failed to get root node of initfs.");
- vfile::vfile root;
- root.bd = &initfs_bd;
- root.dir_entry.type = storage::file_type::directory;
- root.path.absolute = true;
+ utility::string init_path_string("/bin/init.elf", 13);
+ vfile::canon_path init_path;
+ vfile::canonize_path(init_path_string, init_path);
- if (initfs_fs.get_root_node(root.dir_entry.node) !=
+ std::optional<vfile::vfile> init_file;
+ if (vfile::lookup_path(vfs_root, init_path, init_file) !=
storage::fs_result::success)
- print_and_halt("failed to get root node.");
-
- terminal::put_string_sz("initfs");
- dir_tree(root, root, 0);
- print_and_halt("halting.");
+ print_and_halt("failed to look up /bin/init.elf.");
+ if (!init_file)
+ print_and_halt("/bin/init.elf does not exist.");
+
+ terminal::put_string_sz("/bin/init.elf is ");
+ terminal::put_int_decimal(init_file->dir_entry.length);
+ terminal::put_string_sz(" bytes long.\n");
+
+ application::app_instance *init;
+ if (application::create_app(*init_file, init) !=
+ application::create_app_result::success)
+ print_and_halt("failed to parse /bin/init.elf.");
+
+ terminal::put_string_sz("/bin/init.elf loaded:\n instruction pointer 0x");
+ terminal::put_int_hex(init->saved_regs.rip, 8);
+ terminal::put_string_sz("\n stack pointer 0x");
+ terminal::put_int_hex(init->saved_regs.rsp, 8);
+ terminal::put_string_sz("\n ");
+ terminal::put_int_decimal(init->count_mapped_vram_pages() * 2);
+ terminal::put_string_sz(" MiB userspace memory used\n");
+
+ print_mem();
+ terminal::put_string_sz("switching to /bin/init.elf.\n");
+ application::running_app = init;
+ start_user_mode(init->saved_regs.rip, init->saved_regs.rsp, init->p4_paddr);
}
diff --git a/kernel/paging.cpp b/kernel/paging.cpp
index 8c27abc..17b61f4 100644
--- a/kernel/paging.cpp
+++ b/kernel/paging.cpp
@@ -10,9 +10,13 @@ extern "C" {
namespace mercury::kernel::paging {
static constexpr uint64_t kernel_vram_start = 0xffffffffc0000000;
- static constexpr uint64_t kernel_vram_pages = 261888;
- static constexpr uint64_t kernel_stack_bottom = 0xfffffffffff01000;
- static constexpr uint64_t kernel_stack_top = 0xfffffffffffff000;
+ static constexpr uint64_t kernel_vram_end = 0xffffffffffe00000;
+ static constexpr uint64_t kernel_vram_pages =
+ (kernel_vram_end - kernel_vram_start) / 4096;
+ static constexpr uint64_t syscall_stack_bottom = 0xfffffffffff01000;
+ static constexpr uint64_t syscall_stack_top = 0xfffffffffffff000;
+ static constexpr uint64_t interrupt_stack_bottom = 0xffffffffffe01000;
+ static constexpr uint64_t interrupt_stack_top = 0xffffffffffeff000;
static constexpr uint64_t pram_pages = 1 << 23;
static uint64_t pram_usage_bitmap[pram_pages / 64];
@@ -32,25 +36,29 @@ namespace mercury::kernel::paging {
[[gnu::aligned(4096)]] uint64_t kernel_p2[512];
[[gnu::aligned(4096)]] uint64_t kernel_p1s[512 * 512];
- static uint64_t encode_pte(
- uint64_t addr, bool user, bool write, bool execute) {
+ uint64_t kernel_p4e;
+
+ uint64_t encode_pte(
+ uint64_t addr, bool user, bool write, bool execute, bool ps
+ ) {
return (addr & 0x0000ffffffffffff) | (execute ? 0 : (1ULL << 63))
- | (user << 2) | (write << 1) | 1;
+ | (ps << 7) | (user << 2) | (write << 1) | 1;
}
void init_kernel_page_tables(uint64_t kernel_offset) {
__kernel_p4_paddr = (uint64_t)kernel_p4 - kernel_offset;
for (int i = 0; i < 511; ++i)
kernel_p4[i] = 0;
- kernel_p4[511] = encode_pte(
- (uint64_t)kernel_p3 - kernel_offset, false, true, true);
+ kernel_p4e = encode_pte(
+ (uint64_t)kernel_p3 - kernel_offset, false, true, true, false);
+ kernel_p4[511] = kernel_p4e;
for (int i = 0; i < 511; ++i)
kernel_p3[i] = 0;
kernel_p3[511] = encode_pte(
- (uint64_t)kernel_p2 - kernel_offset, false, true, true);
+ (uint64_t)kernel_p2 - kernel_offset, false, true, true, false);
for (int i = 0; i < 512; ++i)
kernel_p2[i] = encode_pte(
- (uint64_t)kernel_p1s + 4096 * i - kernel_offset, false, true, true);
+ (uint64_t)kernel_p1s + 4096 * i - kernel_offset, false, true, true, false);
for (int i = 0; i < 512 * 512; ++i)
kernel_p1s[i] = 0;
}
@@ -58,14 +66,22 @@ namespace mercury::kernel::paging {
void map_kernel_page(
uint64_t paddr, uint64_t vaddr, bool write, bool execute) {
uint64_t i = (vaddr - kernel_vram_start) / 4096;
- kernel_p1s[i] = encode_pte(paddr, false, write, execute);
+ kernel_p1s[i] = encode_pte(paddr, false, write, execute, false);
+ }
+
+ void unmap_kernel_page(uint64_t vaddr) {
+ uint64_t i = (vaddr - kernel_vram_start) / 4096;
+ kernel_p1s[i] = 0;
+ asm volatile (
+ "mov %%cr3, %%rax\nmov %%rax, %%cr3" ::: "%rax"
+ );
}
static uint64_t take_pram_page() {
for (uint64_t i = 0; i < pram_pages / 64; ++i)
- if (pram_usage_bitmap[i] != 0xffffffffffffffff)
+ if (~pram_usage_bitmap[i] != 0)
for (int j = 0; j < 64; ++j)
- if (!(pram_usage_bitmap[i] & (1ULL << j))) {
+ if (~pram_usage_bitmap[i] & (1ULL << j)) {
pram_usage_bitmap[i] |= (1ULL << j);
return 4096 * (i * 64 + j);
}
@@ -73,9 +89,27 @@ namespace mercury::kernel::paging {
return 0;
}
- void map_kernel_stack() {
- for (uint64_t vaddr = kernel_stack_bottom;
- vaddr < kernel_stack_top; vaddr += 4096)
+ uint64_t take_2mib_pram_page() {
+ for (uint64_t i = 0; i < pram_pages / 512; ++i) {
+ for (int j = 0; j < 8; ++j)
+ if (pram_usage_bitmap[i * 8 + j] != 0)
+ goto next_i;
+ for (int j = 0; j < 8; ++j)
+ pram_usage_bitmap[i * 8 + j] = ~0ULL;
+ return 0x200000 * i;
+ next_i:
+ ;
+ }
+ //TODO: handle error
+ return 0;
+ }
+
+ void map_kernel_stacks() {
+ for (uint64_t vaddr = syscall_stack_bottom;
+ vaddr < syscall_stack_top; vaddr += 4096)
+ map_kernel_page(take_pram_page(), vaddr, true, false);
+ for (uint64_t vaddr = interrupt_stack_bottom;
+ vaddr < interrupt_stack_top; vaddr += 4096)
map_kernel_page(take_pram_page(), vaddr, true, false);
}
@@ -103,6 +137,12 @@ namespace mercury::kernel::paging {
return (void *)vaddr;
}
+ void map_new_kernel_page(uint64_t &vaddr_out, uint64_t &paddr_out) {
+ vaddr_out = find_unmapped_vram_region(1);
+ paddr_out = take_pram_page();
+ map_kernel_page(paddr_out, vaddr_out, true, false);
+ }
+
uint64_t get_used_vram_page_count() {
uint64_t count = 0;
for (uint64_t i = 0; i < kernel_vram_pages; ++i)
diff --git a/kernel/syscall.asm b/kernel/syscall.asm
new file mode 100644
index 0000000..56be8a4
--- /dev/null
+++ b/kernel/syscall.asm
@@ -0,0 +1,160 @@
+bits 64
+
+global load_gdt_and_idt
+global start_user_mode
+
+section .rodata
+
+;0x28 picked to align with limine choice
+;0x28 - kernel code
+;0x30 - kernel data
+;0x38 - user data
+;0x40 - user code
+
+gdtr:
+ dw 0x47
+ dq gdt
+
+gdt:
+ dq 0
+ dq 0
+ dq 0
+ dq 0
+ dq 0
+ dq 0x00209b0000000000
+ dq 0x00009b0000000000
+ dq 0x0000fb0000000000
+ dq 0x0020fb0000000000
+
+idtr:
+ dw 4095
+ dq idt
+
+idt:
+ times 256 - ($ - idt) / 16 dq 0
+
+section .text
+
+load_gdt_and_idt:
+ lgdt [gdtr]
+ lidt [idtr]
+ ret
+
+extern syscall_encode_color
+
+encode_color_syscall:
+ call syscall_encode_color
+ mov edi, eax
+ xor rax, rax
+ mov eax, edi
+ xor rdi, rdi
+ xor rsi, rsi
+ xor rdx, rdx
+ jmp syscall_return
+
+extern syscall_get_fb_vaddr
+extern syscall_get_fb_dims
+extern syscall_get_fb_pitch
+
+get_framebuffer_syscall:
+ call syscall_get_fb_vaddr
+ push rax
+ call syscall_get_fb_dims
+ push rax
+ call syscall_get_fb_pitch
+ xor rsi, rsi
+ mov esi, eax
+ pop rdi
+ pop rax
+ xor rdx, rdx
+ jmp syscall_return
+
+extern syscall_copy_framebuffer
+
+draw_framebuffer_syscall:
+ call syscall_copy_framebuffer
+ xor rax, rax
+ xor rdi, rdi
+ xor rsi, rsi
+ xor rdx, rdx
+ jmp syscall_return
+
+bad_syscall:
+ xor rax, rax
+ xor rdi, rdi
+ xor rsi, rsi
+ xor rdx, rdx
+ jmp syscall_return
+
+syscall_entry:
+ mov r11, rsp
+ mov rsp, 0xfffffffffffff000
+ push r11
+ push rcx
+
+ cmp rax, 0
+ je encode_color_syscall
+ cmp rax, 1
+ je get_framebuffer_syscall
+ cmp rax, 2
+ je draw_framebuffer_syscall
+ jmp bad_syscall
+
+syscall_return:
+ xor r8, r8
+ xor r9, r9
+ xor r10, r10
+ xor r11, r11
+ or r11, 0x200
+ pop rcx
+ pop rsp
+
+ o64 sysret
+
+start_user_mode:
+;intended rip in rdi
+;intended rsp in rsi
+;intended p4_paddr in rdx
+
+ mov rax, rdx
+ mov cr3, rax
+
+ ;efer <- efer | 0x1
+ mov rcx, 0xc0000080
+ rdmsr
+ or al, 1
+ wrmsr
+
+ ;lstar <- syscall_entry
+ mov rdx, syscall_entry
+ mov eax, edx
+ shr rdx, 32
+ mov ecx, 0xc0000082
+ wrmsr
+
+ ;star <- 0x0030.0028.0000.0000
+ mov edx, 0x00300028
+ xor eax, eax
+ mov ecx, 0xc0000081
+ wrmsr
+
+ mov rcx, rdi
+ mov rsp, rsi
+ xor r11, r11
+ or r11, 0x200
+
+ xor rax, rax
+ xor rbx, rbx
+ xor rdx, rdx
+ xor rdi, rdi
+ xor rsi, rsi
+ xor rbp, rbp
+ xor r8, r8
+ xor r9, r9
+ xor r10, r10
+ xor r12, r12
+ xor r13, r13
+ xor r14, r14
+ xor r15, r15
+
+ o64 sysret
diff --git a/kernel/syscall.cpp b/kernel/syscall.cpp
new file mode 100644
index 0000000..e91d12d
--- /dev/null
+++ b/kernel/syscall.cpp
@@ -0,0 +1,46 @@
+#include <mercury/kernel/application.hpp>
+#include <mercury/kernel/framebuffer.hpp>
+#include <mercury/kernel/paging.hpp>
+
+using namespace mercury::kernel;
+
+extern "C" uint32_t syscall_encode_color(uint32_t c) {
+ return (uint32_t)framebuffer::encode_color(
+ c & 0xff, (c >> 8) & 0xff, (c >> 16) & 0xff
+ );
+}
+
+extern "C" uint64_t syscall_get_fb_vaddr() {
+ auto *app = application::running_app;
+ if (app->framebuffer_vaddr != 0)
+ return app->framebuffer_vaddr;
+ uint64_t fb_len = framebuffer::dword_pitch * framebuffer::height * 4;
+ uint64_t fb_pages = (fb_len - 1) / 0x200000 + 1;
+ uint64_t vaddr = app->get_free_vaddr_pages(fb_pages);
+ for (uint64_t i = 0; i < fb_pages; ++i) {
+ uint64_t paddr = paging::take_2mib_pram_page();
+ app->map_page(vaddr + i * 0x200000, paddr, true, false, true);
+ }
+ app->framebuffer_vaddr = vaddr;
+ return vaddr;
+}
+
+extern "C" uint64_t syscall_get_fb_dims() {
+ return (uint64_t)(uint32_t)framebuffer::width +
+ ((uint64_t)(uint32_t)framebuffer::height << 32);
+}
+
+extern "C" uint32_t syscall_get_fb_pitch() {
+ return (uint32_t)framebuffer::dword_pitch;
+}
+
+extern "C" void syscall_copy_framebuffer() {
+ auto *app = application::running_app;
+ if (app->framebuffer_vaddr != 0) {
+ const uint32_t *source = (const uint32_t *)app->framebuffer_vaddr;
+ for (int y = 0; y < framebuffer::height; ++y)
+ for (int x = 0; x < framebuffer::width; ++x)
+ framebuffer::vaddr[y * framebuffer::dword_pitch + x]
+ = source[y * framebuffer::dword_pitch + x];
+ }
+}
diff --git a/kernel/terminal.cpp b/kernel/terminal.cpp
index 59e1ee5..1074fe7 100644
--- a/kernel/terminal.cpp
+++ b/kernel/terminal.cpp
@@ -108,4 +108,14 @@ namespace mercury::kernel::terminal {
}
+ static char hex_digits[] = "0123456789abcdef";
+
+ void put_int_hex(uint64_t n, int digits, bool with_dots) {
+ for (int digit = digits - 1; digit >= 0; --digit) {
+ put_char(hex_digits[(n >> (digit * 4)) & 0xf]);
+ if (with_dots && digit % 4 == 0 && digit != 0)
+ put_char('.');
+ }
+ }
+
}
diff --git a/kernel/vfile.cpp b/kernel/vfile.cpp
index 9f549e5..3b9dcb2 100644
--- a/kernel/vfile.cpp
+++ b/kernel/vfile.cpp
@@ -163,6 +163,13 @@ namespace mercury::kernel::vfile {
}
+ storage::fs_result vfile::read_file(
+ uint64_t start, uint64_t length, void *into
+ ) const {
+ return bd->mounted_as->read_bytes_from_file(
+ dir_entry.node, start, length, into);
+ }
+
storage::fs_result lookup_path(
const vfile &root, const canon_path &path, std::optional<vfile> &out
) {