Kernel: Use the GS segment for the per-CPU struct

Right now we're using the FS segment for our per-CPU struct. On x86_64
there's an instruction to switch between a kernel and usermode GS
segment (swapgs) which we could use.

This patch doesn't update the rest of the code to use swapgs but it
prepares for that by using the GS segment instead of the FS segment.
This commit is contained in:
Gunnar Beutner 2021-07-02 14:02:36 +02:00 committed by Andreas Kling
parent 42d197cde7
commit 52f9aaa823
Notes: sideshowbarker 2024-07-18 11:05:17 +09:00
8 changed files with 36 additions and 36 deletions

View File

@ -62,25 +62,25 @@ ALWAYS_INLINE u16 get_gs()
} }
#endif #endif
ALWAYS_INLINE u32 read_fs_u32(u32 offset) ALWAYS_INLINE u32 read_gs_u32(u32 offset)
{ {
u32 val; u32 val;
asm volatile( asm volatile(
"movl %%fs:%a[off], %k[val]" "movl %%gs:%a[off], %k[val]"
: [val] "=r"(val) : [val] "=r"(val)
: [off] "ir"(offset)); : [off] "ir"(offset));
return val; return val;
} }
ALWAYS_INLINE FlatPtr read_fs_ptr(u32 offset) ALWAYS_INLINE FlatPtr read_gs_ptr(u32 offset)
{ {
return read_fs_u32(offset); return read_gs_u32(offset);
} }
ALWAYS_INLINE void write_fs_u32(u32 offset, u32 val) ALWAYS_INLINE void write_gs_u32(u32 offset, u32 val)
{ {
asm volatile( asm volatile(
"movl %k[val], %%fs:%a[off]" ::[off] "ir"(offset), [val] "ir"(val) "movl %k[val], %%gs:%a[off]" ::[off] "ir"(offset), [val] "ir"(val)
: "memory"); : "memory");
} }

View File

@ -21,7 +21,7 @@ namespace Kernel {
#if ARCH(X86_64) #if ARCH(X86_64)
# define MSR_FS_BASE 0xc0000100 # define MSR_FS_BASE 0xc0000100
# define MSR_GS_BASE 0xc0000102 # define MSR_GS_BASE 0xc0000101
#endif #endif
class Thread; class Thread;
@ -241,16 +241,16 @@ public:
ALWAYS_INLINE static Processor& current() ALWAYS_INLINE static Processor& current()
{ {
return *(Processor*)read_fs_ptr(__builtin_offsetof(Processor, m_self)); return *(Processor*)read_gs_ptr(__builtin_offsetof(Processor, m_self));
} }
ALWAYS_INLINE static bool is_initialized() ALWAYS_INLINE static bool is_initialized()
{ {
return return
#if ARCH(I386) #if ARCH(I386)
get_fs() == GDT_SELECTOR_PROC && get_gs() == GDT_SELECTOR_PROC &&
#endif #endif
read_fs_u32(__builtin_offsetof(Processor, m_self)) != 0; read_gs_u32(__builtin_offsetof(Processor, m_self)) != 0;
} }
ALWAYS_INLINE void set_scheduler_data(SchedulerPerProcessorData& scheduler_data) ALWAYS_INLINE void set_scheduler_data(SchedulerPerProcessorData& scheduler_data)
@ -286,19 +286,19 @@ public:
// to another processor, which would lead us to get the wrong thread. // to another processor, which would lead us to get the wrong thread.
// To avoid having to disable interrupts, we can just read the field // To avoid having to disable interrupts, we can just read the field
// directly in an atomic fashion, similar to Processor::current. // directly in an atomic fashion, similar to Processor::current.
return (Thread*)read_fs_ptr(__builtin_offsetof(Processor, m_current_thread)); return (Thread*)read_gs_ptr(__builtin_offsetof(Processor, m_current_thread));
} }
ALWAYS_INLINE static void set_current_thread(Thread& current_thread) ALWAYS_INLINE static void set_current_thread(Thread& current_thread)
{ {
// See comment in Processor::current_thread // See comment in Processor::current_thread
write_fs_u32(__builtin_offsetof(Processor, m_current_thread), FlatPtr(&current_thread)); write_gs_u32(__builtin_offsetof(Processor, m_current_thread), FlatPtr(&current_thread));
} }
ALWAYS_INLINE static Thread* idle_thread() ALWAYS_INLINE static Thread* idle_thread()
{ {
// See comment in Processor::current_thread // See comment in Processor::current_thread
return (Thread*)read_fs_ptr(__builtin_offsetof(Processor, m_idle_thread)); return (Thread*)read_gs_ptr(__builtin_offsetof(Processor, m_idle_thread));
} }
ALWAYS_INLINE u32 get_id() const ALWAYS_INLINE u32 get_id() const
@ -314,7 +314,7 @@ public:
ALWAYS_INLINE static u32 id() ALWAYS_INLINE static u32 id()
{ {
// See comment in Processor::current_thread // See comment in Processor::current_thread
return read_fs_ptr(__builtin_offsetof(Processor, m_cpu)); return read_gs_ptr(__builtin_offsetof(Processor, m_cpu));
} }
ALWAYS_INLINE static bool is_bootstrap_processor() ALWAYS_INLINE static bool is_bootstrap_processor()

View File

@ -58,7 +58,7 @@ static EntropySource s_entropy_source_interrupts { EntropySource::Static::Interr
" mov %ax, %ds\n" \ " mov %ax, %ds\n" \
" mov %ax, %es\n" \ " mov %ax, %es\n" \
" mov $" __STRINGIFY(GDT_SELECTOR_PROC) ", %ax\n" \ " mov $" __STRINGIFY(GDT_SELECTOR_PROC) ", %ax\n" \
" mov %ax, %fs\n" \ " mov %ax, %gs\n" \
" pushl %esp \n" /* set TrapFrame::regs */ \ " pushl %esp \n" /* set TrapFrame::regs */ \
" subl $" __STRINGIFY(TRAP_FRAME_SIZE - 4) ", %esp \n" \ " subl $" __STRINGIFY(TRAP_FRAME_SIZE - 4) ", %esp \n" \
" pushl %esp \n" \ " pushl %esp \n" \
@ -84,7 +84,7 @@ static EntropySource s_entropy_source_interrupts { EntropySource::Static::Interr
" mov %ax, %ds\n" \ " mov %ax, %ds\n" \
" mov %ax, %es\n" \ " mov %ax, %es\n" \
" mov $" __STRINGIFY(GDT_SELECTOR_PROC) ", %ax\n" \ " mov $" __STRINGIFY(GDT_SELECTOR_PROC) ", %ax\n" \
" mov %ax, %fs\n" \ " mov %ax, %gs\n" \
" pushl %esp \n" /* set TrapFrame::regs */ \ " pushl %esp \n" /* set TrapFrame::regs */ \
" subl $" __STRINGIFY(TRAP_FRAME_SIZE - 4) ", %esp \n" \ " subl $" __STRINGIFY(TRAP_FRAME_SIZE - 4) ", %esp \n" \
" pushl %esp \n" \ " pushl %esp \n" \

View File

@ -1092,17 +1092,17 @@ UNMAP_AFTER_INIT void Processor::gdt_init()
tls_descriptor.type = 2; tls_descriptor.type = 2;
write_gdt_entry(GDT_SELECTOR_TLS, tls_descriptor); // tls3 write_gdt_entry(GDT_SELECTOR_TLS, tls_descriptor); // tls3
Descriptor fs_descriptor {}; Descriptor gs_descriptor {};
fs_descriptor.set_base(VirtualAddress { this }); gs_descriptor.set_base(VirtualAddress { this });
fs_descriptor.set_limit(sizeof(Processor) - 1); gs_descriptor.set_limit(sizeof(Processor) - 1);
fs_descriptor.dpl = 0; gs_descriptor.dpl = 0;
fs_descriptor.segment_present = 1; gs_descriptor.segment_present = 1;
fs_descriptor.granularity = 0; gs_descriptor.granularity = 0;
fs_descriptor.operation_size64 = 0; gs_descriptor.operation_size64 = 0;
fs_descriptor.operation_size32 = 1; gs_descriptor.operation_size32 = 1;
fs_descriptor.descriptor_type = 1; gs_descriptor.descriptor_type = 1;
fs_descriptor.type = 2; gs_descriptor.type = 2;
write_gdt_entry(GDT_SELECTOR_PROC, fs_descriptor); // fs0 write_gdt_entry(GDT_SELECTOR_PROC, gs_descriptor); // gs0
#endif #endif
Descriptor tss_descriptor {}; Descriptor tss_descriptor {};
@ -1127,16 +1127,16 @@ UNMAP_AFTER_INIT void Processor::gdt_init()
load_task_register(GDT_SELECTOR_TSS); load_task_register(GDT_SELECTOR_TSS);
#if ARCH(X86_64) #if ARCH(X86_64)
MSR fs_base(MSR_FS_BASE); MSR gs_base(MSR_GS_BASE);
fs_base.set((size_t)this & 0xffffffff, (size_t)this >> 32); gs_base.set((size_t)this & 0xffffffff, (size_t)this >> 32);
#else #else
asm volatile( asm volatile(
"mov %%ax, %%ds\n" "mov %%ax, %%ds\n"
"mov %%ax, %%es\n" "mov %%ax, %%es\n"
"mov %%ax, %%gs\n" "mov %%ax, %%fs\n"
"mov %%ax, %%ss\n" ::"a"(GDT_SELECTOR_DATA0) "mov %%ax, %%ss\n" ::"a"(GDT_SELECTOR_DATA0)
: "memory"); : "memory");
set_fs(GDT_SELECTOR_PROC); set_gs(GDT_SELECTOR_PROC);
#endif #endif
#if ARCH(I386) #if ARCH(I386)

View File

@ -21,7 +21,7 @@ asm(
" mov %ax, %ds\n" " mov %ax, %ds\n"
" mov %ax, %es\n" " mov %ax, %es\n"
" mov $" __STRINGIFY(GDT_SELECTOR_PROC) ", %ax\n" " mov $" __STRINGIFY(GDT_SELECTOR_PROC) ", %ax\n"
" mov %ax, %fs\n" " mov %ax, %gs\n"
" pushl %esp \n" // set TrapFrame::regs " pushl %esp \n" // set TrapFrame::regs
" subl $" __STRINGIFY(TRAP_FRAME_SIZE - 4) ", %esp \n" " subl $" __STRINGIFY(TRAP_FRAME_SIZE - 4) ", %esp \n"
" movl %esp, %ebx \n" // save pointer to TrapFrame " movl %esp, %ebx \n" // save pointer to TrapFrame

View File

@ -174,7 +174,7 @@ FlatPtr Processor::init_context(Thread& thread, bool leave_crit)
regs.es = GDT_SELECTOR_DATA0; regs.es = GDT_SELECTOR_DATA0;
regs.gs = GDT_SELECTOR_DATA0; regs.gs = GDT_SELECTOR_DATA0;
regs.ss = GDT_SELECTOR_DATA0; regs.ss = GDT_SELECTOR_DATA0;
regs.fs = GDT_SELECTOR_PROC; regs.gs = GDT_SELECTOR_PROC;
return stack_top; return stack_top;
} }

View File

@ -38,7 +38,7 @@ NEVER_INLINE void syscall_asm_entry_dummy()
" mov %ax, %ds\n" " mov %ax, %ds\n"
" mov %ax, %es\n" " mov %ax, %es\n"
" mov $" __STRINGIFY(GDT_SELECTOR_PROC) ", %ax\n" " mov $" __STRINGIFY(GDT_SELECTOR_PROC) ", %ax\n"
" mov %ax, %fs\n" " mov %ax, %gs\n"
" cld\n" " cld\n"
" xor %esi, %esi\n" " xor %esi, %esi\n"
" xor %edi, %edi\n" " xor %edi, %edi\n"

View File

@ -102,9 +102,9 @@ Thread::Thread(NonnullRefPtr<Process> process, NonnullOwnPtr<Region> kernel_stac
m_regs.cs = GDT_SELECTOR_CODE0; m_regs.cs = GDT_SELECTOR_CODE0;
m_regs.ds = GDT_SELECTOR_DATA0; m_regs.ds = GDT_SELECTOR_DATA0;
m_regs.es = GDT_SELECTOR_DATA0; m_regs.es = GDT_SELECTOR_DATA0;
m_regs.fs = GDT_SELECTOR_PROC; m_regs.fs = 0;
m_regs.ss = GDT_SELECTOR_DATA0; m_regs.ss = GDT_SELECTOR_DATA0;
m_regs.gs = 0; m_regs.gs = GDT_SELECTOR_PROC;
} else { } else {
m_regs.cs = GDT_SELECTOR_CODE3 | 3; m_regs.cs = GDT_SELECTOR_CODE3 | 3;
m_regs.ds = GDT_SELECTOR_DATA3 | 3; m_regs.ds = GDT_SELECTOR_DATA3 | 3;