stack_bottom:
.skip 1024 * 16 # 16KiB
stack_top:
+interrupt_stack_bottom:
+.skip 1024 * 16 # 16KiB
+.globl interrupt_stack_top
+interrupt_stack_top:
.section .bootstrap_text
.code32
#include "utils.hpp"
#include "serial.hpp"
#include "interrupts.hpp"
+#include "ring3.hpp"
os::idt<32> idt;
+extern "C" os::tss TSS;
+extern "C" char interrupt_stack_top;
extern "C" os::paging::PML4T PML4T;
extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_start> info) {
os::print("Mapping:\n");
os::paging::print_mapping(PML4T);
- while (true) {
- os::hlt();
- }
+ // Allow userspaaaaaaaaace in ring 3. Otherwise, we just immediately page fault.
+ // Will make it a module soon-ish.
+ PML4T.contents[511].base_address()->contents[510].U_S(true);
+ PML4T.contents[511].base_address()->contents[511].U_S(true);
+ PML4T.contents[511].U_S(true);
+
+ os::print("Load ring 3 interrupts stack:\n");
+ os::set_ring0_stack(TSS, std::uint64_t(&interrupt_stack_top));
+ os::print("Load TSS:\n");
+ os::load_tss();
+ os::print("Enable syscalls:\n");
+ os::enable_syscalls();
+ os::print("Trying move to ring 3:\n");
+ os::ftl_to_userspace();
+}
+
+extern "C" std::uint64_t syscall(std::uint64_t in1);
+
+extern "C" void userspaaaaaaaaace() {
+ syscall('a');
+ syscall('b');
+ syscall('c');
+ syscall('\n');
+ while (true) { asm volatile("nop"); }
}
--- /dev/null
+.section .text
+
+.globl ftl_to_userspace
+ftl_to_userspace:
+ mov $userspaaaaaaaaace, %rcx
+ mov $0x202, %r11 # EFLAGS
+ sysretq
+
+.globl syscall_64bit_handler
+syscall_64bit_handler:
+ push %rcx
+ mov %r10, %rcx
+ call syscall_64bit_handler_cpp
+ pop %rcx
+ sysretq
+
+.globl load_tss
+load_tss:
+ mov $GDT.TSS, %ax
+ ltr %ax
+ ret
+
+.globl syscall
+syscall:
+ mov %rcx, %r10
+ syscall
+ ret
--- /dev/null
+#include "ring3.hpp"
+#include "utils.hpp"
+#include "serial.hpp"
+
+void os::set_ring0_stack(os::tss& tss, std::uint64_t stack) {
+ tss.rsp0 = stack;
+}
+
+extern "C" void syscall_64bit_handler();
+
+void os::enable_syscalls() {
+ // Enable bit 0 (SYSCALL Enable) of msr IA32_EFER.
+ // This is required to enable syscall/sysret on x86_64 intel.
+ os::set_msr(0xC0000080, os::get_msr(0xC0000080) | (1 << 0));
+ os::set_msr(0xC0000081,
+ (std::uint64_t(8 - 8 + 0b11) << 48) + // sysret_cs_and_ss (e.g., userspace segments)
+ (std::uint64_t(24 - 8 + 0b00) << 32) + // syscall_cs_and_ss (e.g., kernelspace segments)
+ std::uint64_t(0) // syscall_target_eip, only relevant to 32-bits so useless here
+ );
+ os::set_msr(0xC0000082, std::uint64_t(&syscall_64bit_handler)); // RIP for 64-bit program
+ os::set_msr(0xC0000083, 0); // RIP for 32-bit program, we ignore this one because the OS is only supposed to support programs running with 64 bits.
+ os::set_msr(0xC0000084, 0x00000000); // syscall flag mask, we don't want to change the flags for now.
+}
+
+extern "C" void syscall_64bit_handler_cpp(std::uint64_t v) {
+ os::printc((char)v);
+}
--- /dev/null
+#pragma once
+
+#include <cstdint>
+
+namespace os {
+
+struct __attribute__((packed)) tss {
+ std::uint32_t reserved_1;
+ std::uint64_t rsp0;
+ std::uint64_t rsp1;
+ std::uint64_t rsp2;
+ std::uint64_t reserved_2;
+ std::uint64_t ist1;
+ std::uint64_t ist2;
+ std::uint64_t ist3;
+ std::uint64_t ist4;
+ std::uint64_t ist5;
+ std::uint64_t ist6;
+ std::uint64_t ist7;
+ char reserved_3[10];
+ std::uint16_t iopb;
+};
+
+void set_ring0_stack(tss& tss, std::uint64_t stack);
+extern "C" void load_tss();
+void enable_syscalls();
+extern "C" void ftl_to_userspace();
+
+}