From 4bcd3ed86fbbbf1543b98370a8404ef64d2883b6 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Tue, 15 Apr 2025 23:16:20 +0300 Subject: [PATCH] Kernel: Start working on TLS, add SYS_{SET,GET}_TLS --- kernel/arch/i686/Thread.S | 6 +++++- kernel/include/kernel/GDT.h | 8 ++++++-- kernel/include/kernel/Process.h | 2 ++ kernel/include/kernel/Processor.h | 2 ++ kernel/include/kernel/Thread.h | 5 +++++ kernel/kernel/GDT.cpp | 8 ++++++++ kernel/kernel/Process.cpp | 12 ++++++++++++ kernel/kernel/Processor.cpp | 15 +++++++++++++++ kernel/kernel/Scheduler.cpp | 1 + kernel/kernel/Thread.cpp | 2 ++ userspace/libraries/LibC/include/sys/syscall.h | 2 ++ 11 files changed, 60 insertions(+), 3 deletions(-) diff --git a/kernel/arch/i686/Thread.S b/kernel/arch/i686/Thread.S index abe76971..15960e9b 100644 --- a/kernel/arch/i686/Thread.S +++ b/kernel/arch/i686/Thread.S @@ -41,11 +41,15 @@ start_userspace_thread: call get_thread_start_sp movl %eax, %esp + # ds, es = user data movw $(0x20 | 3), %bx movw %bx, %ds movw %bx, %es - movw %bx, %fs + # gs = thread local + movw $(0x30 | 3), %bx movw %bx, %gs + # fs = 0 xorw %bx, %bx + movw %bx, %fs iret diff --git a/kernel/include/kernel/GDT.h b/kernel/include/kernel/GDT.h index c242d47e..989b3a72 100644 --- a/kernel/include/kernel/GDT.h +++ b/kernel/include/kernel/GDT.h @@ -128,6 +128,10 @@ namespace Kernel #endif } +#if ARCH(i686) + void set_tls(uintptr_t addr); +#endif + private: GDT() = default; @@ -149,8 +153,8 @@ namespace Kernel BAN::Array m_gdt; // null, kernel code, kernel data, user code, user data, tss low, tss high static constexpr uint16_t m_tss_offset = 0x28; #elif ARCH(i686) - BAN::Array m_gdt; // null, kernel code, kernel data, user code, user data, processor data, tss - static constexpr uint16_t m_tss_offset = 0x30; + BAN::Array m_gdt; // null, kernel code, kernel data, user code, user data, processor data, tls, tss + static constexpr uint16_t m_tss_offset = 0x38; #endif TaskStateSegment m_tss; const GDTR m_gdtr { diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index ad199cc5..7ff5da7e 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -174,6 +174,8 @@ namespace Kernel BAN::ErrorOr sys_sigprocmask(int how, const sigset_t* set, sigset_t* oset); BAN::ErrorOr sys_yield(); + BAN::ErrorOr sys_set_tls(void*); + BAN::ErrorOr sys_get_tls(); BAN::ErrorOr sys_pthread_create(const pthread_attr_t* attr, void (*entry)(void*), void* arg); BAN::ErrorOr sys_pthread_exit(void* value); BAN::ErrorOr sys_pthread_join(pthread_t thread, void** value); diff --git a/kernel/include/kernel/Processor.h b/kernel/include/kernel/Processor.h index 996f1350..c7da8b26 100644 --- a/kernel/include/kernel/Processor.h +++ b/kernel/include/kernel/Processor.h @@ -110,6 +110,8 @@ namespace Kernel static void send_smp_message(ProcessorID, const SMPMessage&, bool send_ipi = true); static void broadcast_smp_message(const SMPMessage&); + static void load_tls(); + private: Processor() = default; ~Processor() { ASSERT_NOT_REACHED(); } diff --git a/kernel/include/kernel/Thread.h b/kernel/include/kernel/Thread.h index 92933d49..89448810 100644 --- a/kernel/include/kernel/Thread.h +++ b/kernel/include/kernel/Thread.h @@ -88,6 +88,9 @@ namespace Kernel bool is_userspace() const { return m_is_userspace; } + void set_tls(vaddr_t tls) { m_tls = tls; } + vaddr_t get_tls() const { return m_tls; } + size_t virtual_page_count() const { return (m_kernel_stack ? (m_kernel_stack->size() / PAGE_SIZE) : 0) + (m_userspace_stack ? (m_userspace_stack->size() / PAGE_SIZE) : 0); } size_t physical_page_count() const { return virtual_page_count(); } @@ -121,6 +124,8 @@ namespace Kernel bool m_is_userspace { false }; bool m_delete_process { false }; + vaddr_t m_tls { 0 }; + SchedulerQueue::Node* m_scheduler_node { nullptr }; InterruptStack m_interrupt_stack { }; diff --git a/kernel/kernel/GDT.cpp b/kernel/kernel/GDT.cpp index 302a82ed..f14d816d 100644 --- a/kernel/kernel/GDT.cpp +++ b/kernel/kernel/GDT.cpp @@ -26,12 +26,20 @@ namespace Kernel gdt->write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, data_flags); // user data #if ARCH(i686) gdt->write_entry(0x28, reinterpret_cast(processor), sizeof(Processor), 0x92, 0x4); // processor data + gdt->write_entry(0x30, 0x00000000, 0x00000, 0x00, 0x0); // tls #endif gdt->write_tss(); return gdt; } +#if ARCH(i686) + void GDT::set_tls(uintptr_t addr) + { + write_entry(0x30, addr, 0xFFFF, 0xF2, 0xC); + } +#endif + void GDT::write_entry(uint8_t offset, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags) { ASSERT(offset % sizeof(SegmentDescriptor) == 0); diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index b2b1165f..b49bfea1 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -2037,6 +2037,18 @@ namespace Kernel return 0; } + BAN::ErrorOr Process::sys_set_tls(void* addr) + { + Thread::current().set_tls(reinterpret_cast(addr)); + Processor::load_tls(); + return 0; + } + + BAN::ErrorOr Process::sys_get_tls() + { + return Thread::current().get_tls(); + } + BAN::ErrorOr Process::sys_pthread_create(const pthread_attr_t* attr, void (*entry)(void*), void* arg) { if (attr != nullptr) diff --git a/kernel/kernel/Processor.cpp b/kernel/kernel/Processor.cpp index 50b27243..c0a6fdfb 100644 --- a/kernel/kernel/Processor.cpp +++ b/kernel/kernel/Processor.cpp @@ -10,7 +10,10 @@ extern Kernel::TerminalDriver* g_terminal_driver; namespace Kernel { +#if ARCH(x86_64) + static constexpr uint32_t MSR_IA32_FS_BASE = 0xC0000100; static constexpr uint32_t MSR_IA32_GS_BASE = 0xC0000101; +#endif ProcessorID Processor::s_bsb_id { PROCESSOR_NONE }; BAN::Atomic Processor::s_processor_count { 0 }; @@ -260,6 +263,18 @@ namespace Kernel set_interrupt_state(state); } + void Processor::load_tls() + { + const auto addr = scheduler().current_thread().get_tls(); +#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_tls(addr); +#endif + } + void Processor::send_smp_message(ProcessorID processor_id, const SMPMessage& message, bool send_ipi) { ASSERT(processor_id != current_id()); diff --git a/kernel/kernel/Scheduler.cpp b/kernel/kernel/Scheduler.cpp index 69fa10d6..924a14d2 100644 --- a/kernel/kernel/Scheduler.cpp +++ b/kernel/kernel/Scheduler.cpp @@ -278,6 +278,7 @@ namespace Kernel thread->m_state = Thread::State::Executing; Processor::gdt().set_tss_stack(thread->kernel_stack_top()); + Processor::load_tls(); *interrupt_stack = thread->interrupt_stack(); *interrupt_registers = thread->interrupt_registers(); diff --git a/kernel/kernel/Thread.cpp b/kernel/kernel/Thread.cpp index 4318b2a2..a8713c71 100644 --- a/kernel/kernel/Thread.cpp +++ b/kernel/kernel/Thread.cpp @@ -196,6 +196,8 @@ namespace Kernel thread->m_kernel_stack = TRY(m_kernel_stack->clone(new_process->page_table())); thread->m_userspace_stack = TRY(m_userspace_stack->clone(new_process->page_table())); + thread->m_tls = m_tls; + thread->m_state = State::NotStarted; thread->m_interrupt_stack.ip = ip; diff --git a/userspace/libraries/LibC/include/sys/syscall.h b/userspace/libraries/LibC/include/sys/syscall.h index 273fc7c5..e99792c9 100644 --- a/userspace/libraries/LibC/include/sys/syscall.h +++ b/userspace/libraries/LibC/include/sys/syscall.h @@ -91,6 +91,8 @@ __BEGIN_DECLS O(SYS_SYMLINKAT, symlinkat) \ O(SYS_HARDLINKAT, hardlinkat) \ O(SYS_YIELD, yield) \ + O(SYS_SET_TLS, set_tls) \ + O(SYS_GET_TLS, get_tls) \ O(SYS_PTHREAD_CREATE, pthread_create) \ O(SYS_PTHREAD_EXIT, pthread_exit) \ O(SYS_PTHREAD_JOIN, pthread_join) \