Kernel: Use syscall/sysret for syscalls in x86_64
This commit is contained in:
@@ -15,23 +15,23 @@ namespace Kernel
|
||||
ASSERT(gdt);
|
||||
|
||||
#if ARCH(x86_64)
|
||||
constexpr uint8_t code_flags = 0xA;
|
||||
constexpr uint8_t data_flags = 0xC;
|
||||
gdt->write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null
|
||||
gdt->write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, 0xA); // kernel code
|
||||
gdt->write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, 0xC); // kernel data
|
||||
gdt->write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, 0xC); // user code (32 bit)
|
||||
gdt->write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data
|
||||
gdt->write_entry(0x28, 0x00000000, 0xFFFFF, 0xFA, 0xA); // user code (64 bit)
|
||||
#elif ARCH(i686)
|
||||
constexpr uint8_t code_flags = 0xC;
|
||||
constexpr uint8_t data_flags = 0xC;
|
||||
gdt->write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null
|
||||
gdt->write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, 0xC); // kernel code
|
||||
gdt->write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, 0xC); // kernel data
|
||||
gdt->write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, 0xC); // user code
|
||||
gdt->write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data
|
||||
gdt->write_entry(0x28, reinterpret_cast<uint32_t>(processor), sizeof(Processor), 0x92, 0x4); // processor data
|
||||
gdt->write_entry(0x30, 0x00000000, 0x00000, 0xF2, 0xC); // fsbase
|
||||
gdt->write_entry(0x38, 0x00000000, 0x00000, 0xF2, 0xC); // gsbase
|
||||
#endif
|
||||
|
||||
gdt->write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null
|
||||
gdt->write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, code_flags); // kernel code
|
||||
gdt->write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, data_flags); // kernel data
|
||||
gdt->write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, code_flags); // user code
|
||||
gdt->write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, data_flags); // user data
|
||||
#if ARCH(i686)
|
||||
gdt->write_entry(0x28, reinterpret_cast<uint32_t>(processor), sizeof(Processor), 0x92, 0x4); // processor data
|
||||
gdt->write_entry(0x30, 0x00000000, 0x00000, 0xF2, data_flags); // fsbase
|
||||
gdt->write_entry(0x38, 0x00000000, 0x00000, 0xF2, data_flags); // gsbase
|
||||
#endif
|
||||
gdt->write_tss();
|
||||
|
||||
return gdt;
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
X(160) X(161) X(162) X(163) X(164) X(165) X(166) X(167) X(168) X(169) X(170) X(171) X(172) X(173) X(174) X(175) X(176) X(177) X(178) X(179) X(180) X(181) X(182) X(183) X(184) X(185) X(186) X(187) X(188) X(189) X(190) X(191) \
|
||||
X(192) X(193) X(194) X(195) X(196) X(197) X(198) X(199) X(200) X(201) X(202) X(203) X(204) X(205) X(206) X(207)
|
||||
|
||||
static_assert(Kernel::IRQ_SYSCALL == Kernel::IRQ_VECTOR_BASE + 208);
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
@@ -446,7 +444,9 @@ namespace Kernel
|
||||
extern "C" void asm_yield_handler();
|
||||
extern "C" void asm_ipi_handler();
|
||||
extern "C" void asm_timer_handler();
|
||||
#if ARCH(i686)
|
||||
extern "C" void asm_syscall_handler();
|
||||
#endif
|
||||
|
||||
IDT* IDT::create()
|
||||
{
|
||||
@@ -480,7 +480,9 @@ namespace Kernel
|
||||
idt->register_interrupt_handler(IRQ_YIELD, asm_yield_handler);
|
||||
idt->register_interrupt_handler(IRQ_IPI, asm_ipi_handler);
|
||||
idt->register_interrupt_handler(IRQ_TIMER, asm_timer_handler);
|
||||
#if ARCH(i686)
|
||||
idt->register_syscall_handler(IRQ_SYSCALL, asm_syscall_handler);
|
||||
#endif
|
||||
|
||||
return idt;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,11 @@ namespace Kernel
|
||||
static constexpr uint32_t MSR_IA32_FS_BASE = 0xC0000100;
|
||||
static constexpr uint32_t MSR_IA32_GS_BASE = 0xC0000101;
|
||||
static constexpr uint32_t MSR_IA32_KERNEL_GS_BASE = 0xC0000102;
|
||||
|
||||
static constexpr uint32_t MSR_IA32_EFER = 0xC0000080;
|
||||
static constexpr uint32_t MSR_IA32_STAR = 0xC0000081;
|
||||
static constexpr uint32_t MSR_IA32_LSTAR = 0xC0000082;
|
||||
static constexpr uint32_t MSR_IA32_FMASK = 0xC0000084;
|
||||
#endif
|
||||
|
||||
ProcessorID Processor::s_bsp_id { PROCESSOR_NONE };
|
||||
@@ -30,6 +35,8 @@ namespace Kernel
|
||||
static BAN::Array<Processor, 0xFF> s_processors;
|
||||
static BAN::Array<ProcessorID, 0xFF> s_processor_ids { PROCESSOR_NONE };
|
||||
|
||||
extern "C" void asm_syscall_handler();
|
||||
|
||||
ProcessorID Processor::read_processor_id()
|
||||
{
|
||||
uint32_t id;
|
||||
@@ -87,13 +94,53 @@ namespace Kernel
|
||||
|
||||
// initialize GS
|
||||
#if ARCH(x86_64)
|
||||
// set gs base to pointer to this processor
|
||||
uint64_t ptr = reinterpret_cast<uint64_t>(&processor);
|
||||
uint32_t ptr_hi = ptr >> 32;
|
||||
uint32_t ptr_lo = ptr & 0xFFFFFFFF;
|
||||
asm volatile("wrmsr" :: "d"(ptr_hi), "a"(ptr_lo), "c"(MSR_IA32_GS_BASE));
|
||||
{
|
||||
// set gs base to pointer to this processor
|
||||
const uint64_t val = reinterpret_cast<uint64_t>(&processor);
|
||||
const uint32_t val_hi = val >> 32;
|
||||
const uint32_t val_lo = val & 0xFFFFFFFF;
|
||||
asm volatile("wrmsr" :: "d"(val_hi), "a"(val_lo), "c"(MSR_IA32_GS_BASE));
|
||||
}
|
||||
#elif ARCH(i686)
|
||||
asm volatile("movw $0x28, %%ax; movw %%ax, %%gs" ::: "ax");
|
||||
asm volatile("movw %0, %%gs" :: "r"(0x28));
|
||||
#endif
|
||||
|
||||
#if ARCH(x86_64)
|
||||
// enable syscall instruction
|
||||
asm volatile("rdmsr; orb $1, %%al; wrmsr" :: "c"(MSR_IA32_EFER) : "eax", "edx");
|
||||
|
||||
{
|
||||
union STAR
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32_t : 32;
|
||||
uint16_t sel_ring0;
|
||||
uint16_t sel_ring3;
|
||||
};
|
||||
uint64_t raw;
|
||||
};
|
||||
|
||||
// set kernel and user segments
|
||||
const uint64_t val = STAR { .sel_ring0 = 0x08, .sel_ring3 = 0x18 | 3 }.raw;
|
||||
const uint32_t val_hi = val >> 32;
|
||||
const uint32_t val_lo = val & 0xFFFFFFFF;
|
||||
asm volatile("wrmsr" :: "d"(val_hi), "a"(val_lo), "c"(MSR_IA32_STAR));
|
||||
}
|
||||
{
|
||||
// set syscall handler address
|
||||
const uint64_t val = reinterpret_cast<uint64_t>(&asm_syscall_handler);
|
||||
const uint32_t val_hi = val >> 32;
|
||||
const uint32_t val_lo = val & 0xFFFFFFFF;
|
||||
asm volatile("wrmsr" :: "d"(val_hi), "a"(val_lo), "c"(MSR_IA32_LSTAR));
|
||||
}
|
||||
{
|
||||
// mask DF and IF
|
||||
const uint64_t val = (1 << 10) | (1 << 9);
|
||||
const uint32_t val_hi = val >> 32;
|
||||
const uint32_t val_lo = val & 0xFFFFFFFF;
|
||||
asm volatile("wrmsr" :: "d"(val_hi), "a"(val_lo), "c"(MSR_IA32_FMASK));
|
||||
}
|
||||
#endif
|
||||
|
||||
ASSERT(processor.m_idt);
|
||||
@@ -372,36 +419,17 @@ namespace Kernel
|
||||
|
||||
void Processor::load_segments()
|
||||
{
|
||||
{
|
||||
const auto addr = scheduler().current_thread().get_fsbase();
|
||||
#if ARCH(x86_64)
|
||||
uint32_t ptr_hi = addr >> 32;
|
||||
uint32_t ptr_lo = addr & 0xFFFFFFFF;
|
||||
asm volatile("wrmsr" :: "d"(ptr_hi), "a"(ptr_lo), "c"(MSR_IA32_FS_BASE));
|
||||
#elif ARCH(i686)
|
||||
gdt().set_fsbase(addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
const auto addr = scheduler().current_thread().get_gsbase();
|
||||
#if ARCH(x86_64)
|
||||
uint32_t ptr_hi = addr >> 32;
|
||||
uint32_t ptr_lo = addr & 0xFFFFFFFF;
|
||||
asm volatile("wrmsr" :: "d"(ptr_hi), "a"(ptr_lo), "c"(MSR_IA32_KERNEL_GS_BASE));
|
||||
#elif ARCH(i686)
|
||||
gdt().set_gsbase(addr);
|
||||
#endif
|
||||
}
|
||||
load_fsbase();
|
||||
load_gsbase();
|
||||
}
|
||||
|
||||
void Processor::load_fsbase()
|
||||
{
|
||||
const auto addr = scheduler().current_thread().get_fsbase();
|
||||
#if ARCH(x86_64)
|
||||
uint32_t ptr_hi = addr >> 32;
|
||||
uint32_t ptr_lo = addr & 0xFFFFFFFF;
|
||||
asm volatile("wrmsr" :: "d"(ptr_hi), "a"(ptr_lo), "c"(MSR_IA32_FS_BASE));
|
||||
const uint32_t addr_hi = addr >> 32;
|
||||
const uint32_t addr_lo = addr & 0xFFFFFFFF;
|
||||
asm volatile("wrmsr" :: "d"(addr_hi), "a"(addr_lo), "c"(MSR_IA32_FS_BASE));
|
||||
#elif ARCH(i686)
|
||||
gdt().set_fsbase(addr);
|
||||
#endif
|
||||
@@ -411,9 +439,9 @@ namespace Kernel
|
||||
{
|
||||
const auto addr = scheduler().current_thread().get_gsbase();
|
||||
#if ARCH(x86_64)
|
||||
uint32_t ptr_hi = addr >> 32;
|
||||
uint32_t ptr_lo = addr & 0xFFFFFFFF;
|
||||
asm volatile("wrmsr" :: "d"(ptr_hi), "a"(ptr_lo), "c"(MSR_IA32_KERNEL_GS_BASE));
|
||||
const uint32_t addr_hi = addr >> 32;
|
||||
const uint32_t addr_lo = addr & 0xFFFFFFFF;
|
||||
asm volatile("wrmsr" :: "d"(addr_hi), "a"(addr_lo), "c"(MSR_IA32_KERNEL_GS_BASE));
|
||||
#elif ARCH(i686)
|
||||
gdt().set_gsbase(addr);
|
||||
#endif
|
||||
|
||||
@@ -284,9 +284,14 @@ namespace Kernel
|
||||
thread->set_cpu_time_start();
|
||||
}
|
||||
|
||||
Processor::gdt().set_tss_stack(thread->kernel_stack_top());
|
||||
if (thread->is_userspace())
|
||||
{
|
||||
const vaddr_t kernel_stack_top = thread->kernel_stack_top();
|
||||
Processor::gdt().set_tss_stack(kernel_stack_top);
|
||||
Processor::set_thread_syscall_stack(kernel_stack_top);
|
||||
Processor::load_segments();
|
||||
}
|
||||
|
||||
*interrupt_stack = thread->interrupt_stack();
|
||||
*interrupt_registers = thread->interrupt_registers();
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include <BAN/Bitcast.h>
|
||||
#include <kernel/API/Syscall.h>
|
||||
#include <kernel/Debug.h>
|
||||
#include <kernel/InterruptStack.h>
|
||||
#include <kernel/Process.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
#include <kernel/Syscall.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
#include <termios.h>
|
||||
@@ -40,10 +40,8 @@ namespace Kernel
|
||||
|
||||
static bool is_restartable_syscall(int syscall);
|
||||
|
||||
extern "C" long cpp_syscall_handler(int syscall, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, InterruptStack* interrupt_stack)
|
||||
extern "C" long cpp_syscall_handler(int syscall, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5)
|
||||
{
|
||||
ASSERT(GDT::is_user_segment(interrupt_stack->cs));
|
||||
|
||||
Processor::set_interrupt_state(InterruptState::Enabled);
|
||||
|
||||
Process::current().wait_while_stopped();
|
||||
|
||||
@@ -490,7 +490,11 @@ namespace Kernel
|
||||
write_to_stack(cur_sp, 0x20 | 3);
|
||||
write_to_stack(cur_sp, sp);
|
||||
write_to_stack(cur_sp, 0x202);
|
||||
#if ARCH(x86_64)
|
||||
write_to_stack(cur_sp, 0x28 | 3);
|
||||
#elif ARCH(i686)
|
||||
write_to_stack(cur_sp, 0x18 | 3);
|
||||
#endif
|
||||
write_to_stack(cur_sp, ip);
|
||||
});
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <kernel/Processor.h>
|
||||
#include <kernel/Random.h>
|
||||
#include <kernel/Scheduler.h>
|
||||
#include <kernel/Syscall.h>
|
||||
#include <kernel/Terminal/FramebufferTerminal.h>
|
||||
#include <kernel/Terminal/Serial.h>
|
||||
#include <kernel/Terminal/VirtualTTY.h>
|
||||
|
||||
Reference in New Issue
Block a user