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:
@@ -16,7 +16,7 @@
|
|||||||
#define USER_CODE_SEGMENT 3
|
#define USER_CODE_SEGMENT 3
|
||||||
#define USER_DATA_SEGMENT 4
|
#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_CODE32_SEGMENT 5
|
||||||
#define APM_CODE16_SEGMENT 6
|
#define APM_CODE16_SEGMENT 6
|
||||||
|
|||||||
@@ -10,16 +10,18 @@
|
|||||||
// Note that the ordering of these is important to SYSCALL/SYSRET.
|
// Note that the ordering of these is important to SYSCALL/SYSRET.
|
||||||
#define KERNEL_CODE_SEGMENT 1
|
#define KERNEL_CODE_SEGMENT 1
|
||||||
#define KERNEL_DATA_SEGMENT 2
|
#define KERNEL_DATA_SEGMENT 2
|
||||||
#define USER_DATA_SEGMENT 3
|
#define USER32_CODE_SEGMENT 3
|
||||||
#define USER_CODE_SEGMENT 4
|
#define USER_DATA_SEGMENT 4
|
||||||
|
#define USER_CODE_SEGMENT 5
|
||||||
|
|
||||||
#define BOOT_GDT_SEGMENT_COUNT (USER_CODE_SEGMENT + 1)
|
#define BOOT_GDT_SEGMENT_COUNT (USER_CODE_SEGMENT + 1)
|
||||||
|
|
||||||
#define KERNEL_CODE_SELECTOR ((KERNEL_CODE_SEGMENT << 3) | DPL_KERNEL)
|
#define KERNEL_CODE_SELECTOR ((KERNEL_CODE_SEGMENT << 3) | DPL_KERNEL)
|
||||||
#define KERNEL_DATA_SELECTOR ((KERNEL_DATA_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 USER32_CODE_SELECTOR ((USER32_CODE_SEGMENT << 3) | DPL_USER)
|
||||||
#define USER_DATA_SELECTOR ((USER_DATA_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
|
#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 /* _ASSEMBLER */
|
||||||
|
|
||||||
#endif /* _KERNEL_ARCH_X86_64_DESCRIPTORS_H */
|
#endif /* _KERNEL_ARCH_X86_64_DESCRIPTORS_H */
|
||||||
|
|||||||
@@ -54,6 +54,18 @@
|
|||||||
#define USER_STACK_REGION 0x7f0000000000
|
#define USER_STACK_REGION 0x7f0000000000
|
||||||
#define USER_STACK_REGION_SIZE ((USER_TOP - USER_STACK_REGION) + 1)
|
#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__
|
#else // __x86_64__
|
||||||
|
|
||||||
|
|||||||
@@ -837,6 +837,9 @@ using BKernel::ProcessGroupList;
|
|||||||
#define THREAD_FLAGS_TRAP_FOR_CORE_DUMP 0x1000
|
#define THREAD_FLAGS_TRAP_FOR_CORE_DUMP 0x1000
|
||||||
// core dump in progress; the thread shall not exit the kernel to userland,
|
// core dump in progress; the thread shall not exit the kernel to userland,
|
||||||
// but shall invoke core_dump_trap_thread() instead.
|
// 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 */
|
#endif /* _KERNEL_THREAD_TYPES_H */
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#define TLS_SIZE (TLS_MAX_KEYS * sizeof(void *))
|
#define TLS_SIZE (TLS_MAX_KEYS * sizeof(void *))
|
||||||
|
#define TLS_COMPAT_SIZE (TLS_MAX_KEYS * sizeof(uint32))
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
TLS_BASE_ADDRESS_SLOT = 0,
|
TLS_BASE_ADDRESS_SLOT = 0,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include <boot/kernel_args.h>
|
#include <boot/kernel_args.h>
|
||||||
#include <cpu.h>
|
#include <cpu.h>
|
||||||
|
#include <tls.h>
|
||||||
#include <vm/vm.h>
|
#include <vm/vm.h>
|
||||||
#include <vm/vm_priv.h>
|
#include <vm/vm_priv.h>
|
||||||
|
|
||||||
@@ -41,7 +42,8 @@ class Descriptor {
|
|||||||
public:
|
public:
|
||||||
constexpr Descriptor();
|
constexpr Descriptor();
|
||||||
inline Descriptor(uint32_t first, uint32_t second);
|
inline Descriptor(uint32_t first, uint32_t second);
|
||||||
constexpr Descriptor(DescriptorType type, bool kernelOnly);
|
constexpr Descriptor(DescriptorType type, bool kernelOnly,
|
||||||
|
bool compatMode = false);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
union {
|
union {
|
||||||
@@ -77,6 +79,15 @@ private:
|
|||||||
Descriptor fSecond;
|
Descriptor fSecond;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class UserTLSDescriptor : public Descriptor {
|
||||||
|
public:
|
||||||
|
inline UserTLSDescriptor(uintptr_t base, size_t limit);
|
||||||
|
|
||||||
|
const Descriptor& GetDescriptor() const { return *this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class GlobalDescriptorTable {
|
class GlobalDescriptorTable {
|
||||||
public:
|
public:
|
||||||
constexpr GlobalDescriptorTable();
|
constexpr GlobalDescriptorTable();
|
||||||
@@ -85,10 +96,12 @@ public:
|
|||||||
|
|
||||||
unsigned SetTSS(unsigned cpu,
|
unsigned SetTSS(unsigned cpu,
|
||||||
const TSSDescriptor& tss);
|
const TSSDescriptor& tss);
|
||||||
|
unsigned SetUserTLS(unsigned cpu,
|
||||||
|
addr_t base, size_t limit);
|
||||||
private:
|
private:
|
||||||
static constexpr unsigned kFirstTSS = 5;
|
static constexpr unsigned kFirstTSS = 6;
|
||||||
static constexpr unsigned kDescriptorCount
|
static constexpr unsigned kDescriptorCount
|
||||||
= kFirstTSS + SMP_MAX_CPUS * 2;
|
= kFirstTSS + SMP_MAX_CPUS * 3;
|
||||||
|
|
||||||
alignas(uint64_t) Descriptor fTable[kDescriptorCount];
|
alignas(uint64_t) Descriptor fTable[kDescriptorCount];
|
||||||
};
|
};
|
||||||
@@ -172,7 +185,7 @@ Descriptor::Descriptor(uint32_t first, uint32_t second)
|
|||||||
|
|
||||||
|
|
||||||
constexpr
|
constexpr
|
||||||
Descriptor::Descriptor(DescriptorType type, bool kernelOnly)
|
Descriptor::Descriptor(DescriptorType type, bool kernelOnly, bool compatMode)
|
||||||
:
|
:
|
||||||
fLimit0(-1),
|
fLimit0(-1),
|
||||||
fBase0(0),
|
fBase0(0),
|
||||||
@@ -182,8 +195,8 @@ Descriptor::Descriptor(DescriptorType type, bool kernelOnly)
|
|||||||
fPresent(1),
|
fPresent(1),
|
||||||
fLimit1(0xf),
|
fLimit1(0xf),
|
||||||
fUnused(0),
|
fUnused(0),
|
||||||
fLong(is_code_segment(type) ? 1 : 0),
|
fLong(is_code_segment(type) && !compatMode ? 1 : 0),
|
||||||
fDB(is_code_segment(type) ? 0 : 1),
|
fDB(is_code_segment(type) && !compatMode ? 0 : 1),
|
||||||
fGranularity(1),
|
fGranularity(1),
|
||||||
fBase1(0)
|
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
|
constexpr
|
||||||
GlobalDescriptorTable::GlobalDescriptorTable()
|
GlobalDescriptorTable::GlobalDescriptorTable()
|
||||||
:
|
:
|
||||||
@@ -217,6 +240,7 @@ GlobalDescriptorTable::GlobalDescriptorTable()
|
|||||||
Descriptor(),
|
Descriptor(),
|
||||||
Descriptor(DescriptorType::CodeExecuteOnly, true),
|
Descriptor(DescriptorType::CodeExecuteOnly, true),
|
||||||
Descriptor(DescriptorType::DataWritable, true),
|
Descriptor(DescriptorType::DataWritable, true),
|
||||||
|
Descriptor(DescriptorType::CodeExecuteOnly, false, true),
|
||||||
Descriptor(DescriptorType::DataWritable, false),
|
Descriptor(DescriptorType::DataWritable, false),
|
||||||
Descriptor(DescriptorType::CodeExecuteOnly, false),
|
Descriptor(DescriptorType::CodeExecuteOnly, false),
|
||||||
}
|
}
|
||||||
@@ -244,7 +268,7 @@ GlobalDescriptorTable::Load() const
|
|||||||
unsigned
|
unsigned
|
||||||
GlobalDescriptorTable::SetTSS(unsigned cpu, const TSSDescriptor& tss)
|
GlobalDescriptorTable::SetTSS(unsigned cpu, const TSSDescriptor& tss)
|
||||||
{
|
{
|
||||||
auto index = kFirstTSS + cpu * 2;
|
auto index = kFirstTSS + cpu * 3;
|
||||||
ASSERT(index + 1 < kDescriptorCount);
|
ASSERT(index + 1 < kDescriptorCount);
|
||||||
fTable[index] = tss.GetLower();
|
fTable[index] = tss.GetLower();
|
||||||
fTable[index + 1] = tss.GetUpper();
|
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
|
constexpr
|
||||||
InterruptDescriptor::InterruptDescriptor(uintptr_t isr, unsigned ist,
|
InterruptDescriptor::InterruptDescriptor(uintptr_t isr, unsigned ist,
|
||||||
bool kernelOnly)
|
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(uintptr_t(&gCPU[cpu].arch.tss), sizeof(struct tss)));
|
||||||
TSSDescriptor::LoadTSS(tssIndex);
|
TSSDescriptor::LoadTSS(tssIndex);
|
||||||
|
|
||||||
|
sGDT.SetUserTLS(cpu, 0, TLS_COMPAT_SIZE);
|
||||||
|
|
||||||
new(&sIDT) InterruptDescriptorTable;
|
new(&sIDT) InterruptDescriptorTable;
|
||||||
sIDT.Load();
|
sIDT.Load();
|
||||||
}
|
}
|
||||||
@@ -399,3 +436,9 @@ x86_descriptors_init(kernel_args* args)
|
|||||||
table[19] = x86_unexpected_exception; // SIMD Floating-Point Exception (#XF)
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -42,10 +42,10 @@ init_syscall_registers(void* dummy, int cpuNum)
|
|||||||
// From this we get:
|
// From this we get:
|
||||||
// - Entry CS = KERNEL_CODE_SELECTOR
|
// - Entry CS = KERNEL_CODE_SELECTOR
|
||||||
// - Entry SS = KERNEL_CODE_SELECTOR + 8 = KERNEL_DATA_SELECTOR
|
// - Entry SS = KERNEL_CODE_SELECTOR + 8 = KERNEL_DATA_SELECTOR
|
||||||
// - Return CS = KERNEL_DATA_SELECTOR + 16 = USER_CODE_SELECTOR
|
// - Return CS = USER32_CODE_SELECTOR + 16 = USER_CODE_SELECTOR
|
||||||
// - Return SS = KERNEL_DATA_SELECTOR + 8 = USER_DATA_SLECTORG
|
// - Return SS = USER32_CODE_SELECTOR + 8 = USER_DATA_SELECTOR
|
||||||
x86_write_msr(IA32_MSR_STAR, ((uint64)(KERNEL_DATA_SELECTOR | 3) << 48)
|
x86_write_msr(IA32_MSR_STAR, ((uint64)(USER32_CODE_SELECTOR) << 48)
|
||||||
| ((uint64)KERNEL_CODE_SELECTOR << 32));
|
| ((uint64)(KERNEL_CODE_SELECTOR) << 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user