From 27b32ee02c3ba1278e17c41fdd2c1768062ee99e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Thu, 3 May 2018 19:54:33 +0200 Subject: [PATCH] kernel/x86_64: adjust descriptors tables for compatibility mode. * also adjust BOOT_GDT_SEGMENT_COUNT for x86, the definition is used by the boot loader. * add some 32-bit definitions. * add a UserTLSDescriptor class, this will be used by 32-bit threads. Change-Id: I5b1d978969a1ce97091a16c9ec2ad7c0ca831656 --- .../private/kernel/arch/x86/32/descriptors.h | 2 +- .../private/kernel/arch/x86/64/descriptors.h | 13 +++-- headers/private/kernel/arch/x86/arch_kernel.h | 12 ++++ headers/private/kernel/thread_types.h | 5 +- headers/private/system/tls.h | 1 + src/system/kernel/arch/x86/64/descriptors.cpp | 57 ++++++++++++++++--- src/system/kernel/arch/x86/64/syscalls.cpp | 8 +-- 7 files changed, 81 insertions(+), 17 deletions(-) diff --git a/headers/private/kernel/arch/x86/32/descriptors.h b/headers/private/kernel/arch/x86/32/descriptors.h index 535c6a1d5f..2aa3941a71 100644 --- a/headers/private/kernel/arch/x86/32/descriptors.h +++ b/headers/private/kernel/arch/x86/32/descriptors.h @@ -16,7 +16,7 @@ #define USER_CODE_SEGMENT 3 #define USER_DATA_SEGMENT 4 -#define BOOT_GDT_SEGMENT_COUNT (USER_DATA_SEGMENT + 1) +#define BOOT_GDT_SEGMENT_COUNT (USER_DATA_SEGMENT + 2) // match x86_64 #define APM_CODE32_SEGMENT 5 #define APM_CODE16_SEGMENT 6 diff --git a/headers/private/kernel/arch/x86/64/descriptors.h b/headers/private/kernel/arch/x86/64/descriptors.h index e359741d63..82a44e277e 100644 --- a/headers/private/kernel/arch/x86/64/descriptors.h +++ b/headers/private/kernel/arch/x86/64/descriptors.h @@ -10,16 +10,18 @@ // Note that the ordering of these is important to SYSCALL/SYSRET. #define KERNEL_CODE_SEGMENT 1 #define KERNEL_DATA_SEGMENT 2 -#define USER_DATA_SEGMENT 3 -#define USER_CODE_SEGMENT 4 +#define USER32_CODE_SEGMENT 3 +#define USER_DATA_SEGMENT 4 +#define USER_CODE_SEGMENT 5 #define BOOT_GDT_SEGMENT_COUNT (USER_CODE_SEGMENT + 1) #define KERNEL_CODE_SELECTOR ((KERNEL_CODE_SEGMENT << 3) | DPL_KERNEL) #define KERNEL_DATA_SELECTOR ((KERNEL_DATA_SEGMENT << 3) | DPL_KERNEL) -#define USER_CODE_SELECTOR ((USER_CODE_SEGMENT << 3) | DPL_USER) -#define USER_DATA_SELECTOR ((USER_DATA_SEGMENT << 3) | DPL_USER) +#define USER32_CODE_SELECTOR ((USER32_CODE_SEGMENT << 3) | DPL_USER) +#define USER_CODE_SELECTOR ((USER_CODE_SEGMENT << 3) | DPL_USER) +#define USER_DATA_SELECTOR ((USER_DATA_SEGMENT << 3) | DPL_USER) #ifndef _ASSEMBLER @@ -90,6 +92,9 @@ set_segment_descriptor(segment_descriptor* desc, uint8 type, uint8 dpl) } +unsigned x86_64_set_user_tls_segment_base(int cpu, addr_t base); + + #endif /* _ASSEMBLER */ #endif /* _KERNEL_ARCH_X86_64_DESCRIPTORS_H */ diff --git a/headers/private/kernel/arch/x86/arch_kernel.h b/headers/private/kernel/arch/x86/arch_kernel.h index 3effe2da51..931176bcc6 100644 --- a/headers/private/kernel/arch/x86/arch_kernel.h +++ b/headers/private/kernel/arch/x86/arch_kernel.h @@ -54,6 +54,18 @@ #define USER_STACK_REGION 0x7f0000000000 #define USER_STACK_REGION_SIZE ((USER_TOP - USER_STACK_REGION) + 1) +#ifdef _COMPAT_MODE + +#define USER32_SIZE 0x100000000 +#define USER32_TOP (USER_BASE + (USER32_SIZE - 1)) + +#define KERNEL_USER32_DATA_BASE 0x60000000 + +#define USER32_STACK_REGION 0x70000000 +#define USER32_STACK_REGION_SIZE ((USER32_TOP - USER32_STACK_REGION) + 1) + +#endif // _COMPAT_MODE + #else // __x86_64__ diff --git a/headers/private/kernel/thread_types.h b/headers/private/kernel/thread_types.h index 720a221c17..33a535c708 100644 --- a/headers/private/kernel/thread_types.h +++ b/headers/private/kernel/thread_types.h @@ -837,6 +837,9 @@ using BKernel::ProcessGroupList; #define THREAD_FLAGS_TRAP_FOR_CORE_DUMP 0x1000 // core dump in progress; the thread shall not exit the kernel to userland, // but shall invoke core_dump_trap_thread() instead. - +#ifdef _COMPAT_MODE +#define THREAD_FLAGS_COMPAT_MODE 0x2000 + // the thread runs a compatibility mode (for instance IA32 on x86_64). +#endif #endif /* _KERNEL_THREAD_TYPES_H */ diff --git a/headers/private/system/tls.h b/headers/private/system/tls.h index 751332e33f..f173755c56 100644 --- a/headers/private/system/tls.h +++ b/headers/private/system/tls.h @@ -10,6 +10,7 @@ #define TLS_SIZE (TLS_MAX_KEYS * sizeof(void *)) +#define TLS_COMPAT_SIZE (TLS_MAX_KEYS * sizeof(uint32)) enum { TLS_BASE_ADDRESS_SLOT = 0, diff --git a/src/system/kernel/arch/x86/64/descriptors.cpp b/src/system/kernel/arch/x86/64/descriptors.cpp index f4fee71dd3..3e516f0134 100644 --- a/src/system/kernel/arch/x86/64/descriptors.cpp +++ b/src/system/kernel/arch/x86/64/descriptors.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -41,7 +42,8 @@ class Descriptor { public: constexpr Descriptor(); inline Descriptor(uint32_t first, uint32_t second); - constexpr Descriptor(DescriptorType type, bool kernelOnly); + constexpr Descriptor(DescriptorType type, bool kernelOnly, + bool compatMode = false); protected: union { @@ -77,6 +79,15 @@ private: Descriptor fSecond; }; + +class UserTLSDescriptor : public Descriptor { +public: + inline UserTLSDescriptor(uintptr_t base, size_t limit); + + const Descriptor& GetDescriptor() const { return *this; } +}; + + class GlobalDescriptorTable { public: constexpr GlobalDescriptorTable(); @@ -85,10 +96,12 @@ public: unsigned SetTSS(unsigned cpu, const TSSDescriptor& tss); + unsigned SetUserTLS(unsigned cpu, + addr_t base, size_t limit); private: - static constexpr unsigned kFirstTSS = 5; + static constexpr unsigned kFirstTSS = 6; static constexpr unsigned kDescriptorCount - = kFirstTSS + SMP_MAX_CPUS * 2; + = kFirstTSS + SMP_MAX_CPUS * 3; alignas(uint64_t) Descriptor fTable[kDescriptorCount]; }; @@ -172,7 +185,7 @@ Descriptor::Descriptor(uint32_t first, uint32_t second) constexpr -Descriptor::Descriptor(DescriptorType type, bool kernelOnly) +Descriptor::Descriptor(DescriptorType type, bool kernelOnly, bool compatMode) : fLimit0(-1), fBase0(0), @@ -182,8 +195,8 @@ Descriptor::Descriptor(DescriptorType type, bool kernelOnly) fPresent(1), fLimit1(0xf), fUnused(0), - fLong(is_code_segment(type) ? 1 : 0), - fDB(is_code_segment(type) ? 0 : 1), + fLong(is_code_segment(type) && !compatMode ? 1 : 0), + fDB(is_code_segment(type) && !compatMode ? 0 : 1), fGranularity(1), fBase1(0) { @@ -210,6 +223,16 @@ TSSDescriptor::LoadTSS(unsigned index) } +UserTLSDescriptor::UserTLSDescriptor(uintptr_t base, size_t limit) + : Descriptor(DescriptorType::DataWritable, false) +{ + fLimit0 = static_cast(limit); + fBase0 = base & 0xffffff; + fLimit1 = (limit >> 16) & 0xf; + fBase1 = static_cast(base >> 24); +} + + constexpr GlobalDescriptorTable::GlobalDescriptorTable() : @@ -217,6 +240,7 @@ GlobalDescriptorTable::GlobalDescriptorTable() Descriptor(), Descriptor(DescriptorType::CodeExecuteOnly, true), Descriptor(DescriptorType::DataWritable, true), + Descriptor(DescriptorType::CodeExecuteOnly, false, true), Descriptor(DescriptorType::DataWritable, false), Descriptor(DescriptorType::CodeExecuteOnly, false), } @@ -244,7 +268,7 @@ GlobalDescriptorTable::Load() const unsigned GlobalDescriptorTable::SetTSS(unsigned cpu, const TSSDescriptor& tss) { - auto index = kFirstTSS + cpu * 2; + auto index = kFirstTSS + cpu * 3; ASSERT(index + 1 < kDescriptorCount); fTable[index] = tss.GetLower(); fTable[index + 1] = tss.GetUpper(); @@ -252,6 +276,17 @@ GlobalDescriptorTable::SetTSS(unsigned cpu, const TSSDescriptor& tss) } +unsigned +GlobalDescriptorTable::SetUserTLS(unsigned cpu, uintptr_t base, size_t limit) +{ + auto index = kFirstTSS + cpu * 3 + 2; + ASSERT(index + 1 < kDescriptorCount); + UserTLSDescriptor desc(base, limit); + fTable[index] = desc.GetDescriptor(); + return index; +} + + constexpr InterruptDescriptor::InterruptDescriptor(uintptr_t isr, unsigned ist, bool kernelOnly) @@ -361,6 +396,8 @@ x86_descriptors_preboot_init_percpu(kernel_args* args, int cpu) TSSDescriptor(uintptr_t(&gCPU[cpu].arch.tss), sizeof(struct tss))); TSSDescriptor::LoadTSS(tssIndex); + sGDT.SetUserTLS(cpu, 0, TLS_COMPAT_SIZE); + new(&sIDT) InterruptDescriptorTable; sIDT.Load(); } @@ -399,3 +436,9 @@ x86_descriptors_init(kernel_args* args) table[19] = x86_unexpected_exception; // SIMD Floating-Point Exception (#XF) } + +unsigned +x86_64_set_user_tls_segment_base(int cpu, addr_t base) +{ + return sGDT.SetUserTLS(cpu, base, TLS_COMPAT_SIZE); +} diff --git a/src/system/kernel/arch/x86/64/syscalls.cpp b/src/system/kernel/arch/x86/64/syscalls.cpp index 7bcfeda5ae..907dd4989d 100644 --- a/src/system/kernel/arch/x86/64/syscalls.cpp +++ b/src/system/kernel/arch/x86/64/syscalls.cpp @@ -42,10 +42,10 @@ init_syscall_registers(void* dummy, int cpuNum) // From this we get: // - Entry CS = KERNEL_CODE_SELECTOR // - Entry SS = KERNEL_CODE_SELECTOR + 8 = KERNEL_DATA_SELECTOR - // - Return CS = KERNEL_DATA_SELECTOR + 16 = USER_CODE_SELECTOR - // - Return SS = KERNEL_DATA_SELECTOR + 8 = USER_DATA_SLECTORG - x86_write_msr(IA32_MSR_STAR, ((uint64)(KERNEL_DATA_SELECTOR | 3) << 48) - | ((uint64)KERNEL_CODE_SELECTOR << 32)); + // - Return CS = USER32_CODE_SELECTOR + 16 = USER_CODE_SELECTOR + // - Return SS = USER32_CODE_SELECTOR + 8 = USER_DATA_SELECTOR + x86_write_msr(IA32_MSR_STAR, ((uint64)(USER32_CODE_SELECTOR) << 48) + | ((uint64)(KERNEL_CODE_SELECTOR) << 32)); }