MSR and syscall changes

- Moved MSR code to separate files with an enum class
- Implemented syscall_enable in C++ using new MSR calls
This commit is contained in:
Justin C. Miller
2018-09-15 00:37:49 -07:00
parent 62c559043d
commit 1308864061
9 changed files with 78 additions and 61 deletions

View File

@@ -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<uint64_t>(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)
{

View File

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

View File

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

18
src/kernel/msr.cpp Normal file
View File

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

27
src/kernel/msr.h Normal file
View File

@@ -0,0 +1,27 @@
#pragma once
/// \file msr.h
/// Routines and definitions for dealing with Model-Specific Registers
#include <stdint.h>
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);

View File

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

View File

@@ -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<addr_t>(&syscall_handler_prelude));
// IA32_FMASK - FLAGS mask inside syscall
wrmsr(msr::ia32_fmask, 0x200);
}
addr_t

View File

@@ -3,6 +3,8 @@
#include <stdint.h>
#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 &);

View File

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