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
This commit is contained in:
Jérôme Duval 2018-05-03 19:54:33 +02:00
parent 6692e4c87f
commit 27b32ee02c
7 changed files with 81 additions and 17 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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__

View File

@ -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 */

View File

@ -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,

View File

@ -9,6 +9,7 @@
#include <boot/kernel_args.h>
#include <cpu.h>
#include <tls.h>
#include <vm/vm.h>
#include <vm/vm_priv.h>
@ -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<uint16_t>(limit);
fBase0 = base & 0xffffff;
fLimit1 = (limit >> 16) & 0xf;
fBase1 = static_cast<uint8_t>(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);
}

View File

@ -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));
}