From 13088640618dec3c15c6902bd1ad91c2181c1030 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Sat, 15 Sep 2018 00:37:49 -0700 Subject: [PATCH] MSR and syscall changes - Moved MSR code to separate files with an enum class - Implemented syscall_enable in C++ using new MSR calls --- src/kernel/io.cpp | 16 ---------------- src/kernel/io.h | 10 ---------- src/kernel/main.cpp | 2 +- src/kernel/msr.cpp | 18 ++++++++++++++++++ src/kernel/msr.h | 27 +++++++++++++++++++++++++++ src/kernel/scheduler.cpp | 7 +++---- src/kernel/syscall.cpp | 25 +++++++++++++++++++++++++ src/kernel/syscall.h | 4 +++- src/kernel/syscall.s | 30 +----------------------------- 9 files changed, 78 insertions(+), 61 deletions(-) create mode 100644 src/kernel/msr.cpp create mode 100644 src/kernel/msr.h diff --git a/src/kernel/io.cpp b/src/kernel/io.cpp index f6a9830..c9ed88f 100644 --- a/src/kernel/io.cpp +++ b/src/kernel/io.cpp @@ -14,22 +14,6 @@ outb(uint16_t port, uint8_t val) __asm__ __volatile__ ( "outb %0, %1" :: "a"(val), "Nd"(port) ); } -uint64_t -rdmsr(uint64_t addr) -{ - uint32_t low, high; - __asm__ __volatile__ ("rdmsr" : "=a"(low), "=d"(high) : "c"(addr)); - return (static_cast(high) << 32) | low; -} - -void -wrmsr(uint64_t addr, uint64_t value) -{ - uint32_t low = value & 0xffffffff; - uint32_t high = value >> 32; - __asm__ __volatile__ ("wrmsr" :: "c"(addr), "a"(low), "d"(high)); -} - void io_wait(unsigned times) { diff --git a/src/kernel/io.h b/src/kernel/io.h index 43e55cd..ebfe6fe 100644 --- a/src/kernel/io.h +++ b/src/kernel/io.h @@ -14,16 +14,6 @@ uint8_t inb(uint16_t port); /// \arg val The byte to write void outb(uint16_t port, uint8_t val); -/// Read the value of a MSR -/// \arg addr The MSR address -/// \returns The current value of the MSR -uint64_t rdmsr(uint64_t addr); - -/// Write to a MSR -/// \arg addr The MSR address -/// \arg value The value to write -void wrmsr(uint64_t addr, uint64_t value); - /// Pause briefly by doing IO to port 0x80 /// \arg times Number of times to delay by writing void io_wait(unsigned times = 1); diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index 840536f..3977adc 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -18,10 +18,10 @@ #include "scheduler.h" #include "screen.h" #include "serial.h" +#include "syscall.h" extern "C" { void kernel_main(popcorn_data *header); - void syscall_enable(); void *__bss_start, *__bss_end; } diff --git a/src/kernel/msr.cpp b/src/kernel/msr.cpp new file mode 100644 index 0000000..d43c1fc --- /dev/null +++ b/src/kernel/msr.cpp @@ -0,0 +1,18 @@ +#include "msr.h" + +uint64_t +rdmsr(msr addr) +{ + uint32_t low, high; + __asm__ __volatile__ ("rdmsr" : "=a"(low), "=d"(high) : "c"(addr)); + return (static_cast(high) << 32) | low; +} + +void +wrmsr(msr addr, uint64_t value) +{ + uint32_t low = value & 0xffffffff; + uint32_t high = value >> 32; + __asm__ __volatile__ ("wrmsr" :: "c"(addr), "a"(low), "d"(high)); +} + diff --git a/src/kernel/msr.h b/src/kernel/msr.h new file mode 100644 index 0000000..4d26425 --- /dev/null +++ b/src/kernel/msr.h @@ -0,0 +1,27 @@ +#pragma once +/// \file msr.h +/// Routines and definitions for dealing with Model-Specific Registers + +#include + +enum class msr : uint32_t +{ + ia32_efer = 0xc0000080, + ia32_star = 0xc0000081, + ia32_lstar = 0xc0000082, + ia32_fmask = 0xc0000084, + + ia32_gs_base = 0xc0000101, + ia32_kernel_gs_base = 0xc0000102 +}; + +/// Read the value of a MSR +/// \arg addr The MSR address +/// \returns The current value of the MSR +uint64_t rdmsr(msr addr); + +/// Write to a MSR +/// \arg addr The MSR address +/// \arg value The value to write +void wrmsr(msr addr, uint64_t value); + diff --git a/src/kernel/scheduler.cpp b/src/kernel/scheduler.cpp index 7671241..159cc2c 100644 --- a/src/kernel/scheduler.cpp +++ b/src/kernel/scheduler.cpp @@ -5,6 +5,7 @@ #include "interrupts.h" #include "io.h" #include "log.h" +#include "msr.h" #include "page_manager.h" #include "scheduler.h" @@ -194,12 +195,10 @@ scheduler::schedule(addr_t rsp0) m_current = m_runlists[pri].pop_front(); rsp0 = m_current->rsp; - static const uint64_t ia32_gs_base = 0xc0000101; - static const uint64_t ia32_kernel_gs_base = 0xc0000102; - // Set rsp0 to after the end of the about-to-be-popped cpu state tss_set_stack(0, rsp0 + sizeof(cpu_state)); - wrmsr(ia32_gs_base, rsp0); + wrmsr(msr::ia32_kernel_gs_base, rsp0); + log::debug(logs::task, "Scheduler set kernel_gs_base to %016lx", rsp0); // Swap page tables page_table *pml4 = m_current->pml4; diff --git a/src/kernel/syscall.cpp b/src/kernel/syscall.cpp index 6f34b2d..ac780cf 100644 --- a/src/kernel/syscall.cpp +++ b/src/kernel/syscall.cpp @@ -1,11 +1,36 @@ #include "console.h" #include "cpu.h" #include "debug.h" +#include "msr.h" #include "scheduler.h" #include "syscall.h" extern "C" { void _halt(); + void syscall_handler_prelude(); +} + +void +syscall_enable() +{ + // IA32_EFER - set bit 0, syscall enable + uint64_t efer = rdmsr(msr::ia32_efer); + wrmsr(msr::ia32_efer, efer|1); + + // IA32_STAR - high 32 bits contain k+u CS + // Kernel CS: GDT[1] ring 0 bits[47:32] + // User CS: GDT[3] ring 3 bits[63:48] + uint64_t star = + (((1ull << 3) | 0) << 32) | + (((3ull << 3) | 3) << 48); + wrmsr(msr::ia32_star, star); + + // IA32_LSTAR - RIP for syscall + wrmsr(msr::ia32_lstar, + reinterpret_cast(&syscall_handler_prelude)); + + // IA32_FMASK - FLAGS mask inside syscall + wrmsr(msr::ia32_fmask, 0x200); } addr_t diff --git a/src/kernel/syscall.h b/src/kernel/syscall.h index cb9e22c..bbb1570 100644 --- a/src/kernel/syscall.h +++ b/src/kernel/syscall.h @@ -3,6 +3,8 @@ #include #include "kutil/memory.h" +struct cpu_state; + enum class syscall : uint64_t { noop, @@ -13,6 +15,6 @@ enum class syscall : uint64_t last_syscall }; -struct cpu_state; +void syscall_enable(); addr_t syscall_dispatch(addr_t, const cpu_state &); diff --git a/src/kernel/syscall.s b/src/kernel/syscall.s index 109f9b0..94c5535 100644 --- a/src/kernel/syscall.s +++ b/src/kernel/syscall.s @@ -1,35 +1,7 @@ %include "push_all.inc" -global syscall_enable -syscall_enable: - ; IA32_EFER - set bit 0, syscall enable - mov rcx, 0xc0000080 - rdmsr - or rax, 0x1 - wrmsr - - ; IA32_STAR - cs for syscall - mov rcx, 0xc0000081 - mov rax, 0 ; not used - mov rdx, 0x00180008 ; GDT:3 (user code), GDT:1 (kernel code) - wrmsr - - ; IA32_LSTAR - RIP for syscall - mov rcx, 0xc0000082 - lea rax, [rel syscall_handler_prelude] - mov rdx, rax - shr rdx, 32 - wrmsr - - ; IA32_FMASK - FLAGS mask inside syscall - mov rcx, 0xc0000084 - mov rax, 0x200 - mov rdx, 0 - wrmsr - - ret - extern syscall_handler +global syscall_handler_prelude syscall_handler_prelude: push 0 ; ss, doesn't matter here push rsp