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:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
18
src/kernel/msr.cpp
Normal 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
27
src/kernel/msr.h
Normal 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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 &);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user