179 lines
3.8 KiB
C
179 lines
3.8 KiB
C
/*
|
|
* Copyright 2012, Alex Smith, alex@alex-smith.me.uk.
|
|
* Distributed under the terms of the MIT License.
|
|
*/
|
|
#ifndef _KERNEL_ARCH_X86_64_DESCRIPTORS_H
|
|
#define _KERNEL_ARCH_X86_64_DESCRIPTORS_H
|
|
|
|
|
|
// Segment definitions.
|
|
// 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 TSS_BASE_SEGMENT 5
|
|
|
|
#define TSS_SEGMENT(cpu) (TSS_BASE_SEGMENT + cpu * 2)
|
|
|
|
#define GDT_SEGMENT_COUNT (TSS_BASE_SEGMENT + SMP_MAX_CPUS * 2)
|
|
|
|
|
|
#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)
|
|
|
|
|
|
#ifndef _ASSEMBLER
|
|
|
|
|
|
// Structure of a segment descriptor.
|
|
struct segment_descriptor {
|
|
uint32 limit0 : 16;
|
|
uint32 base0 : 24;
|
|
uint32 type : 4;
|
|
uint32 desc_type : 1;
|
|
uint32 dpl : 2;
|
|
uint32 present : 1;
|
|
uint32 limit1 : 4;
|
|
uint32 available : 1;
|
|
uint32 long_mode : 1;
|
|
uint32 d_b : 1;
|
|
uint32 granularity : 1;
|
|
uint32 base1 : 8;
|
|
} _PACKED;
|
|
|
|
// Structure of a TSS segment descriptor.
|
|
struct tss_descriptor {
|
|
uint32 limit0 : 16;
|
|
uint32 base0 : 24;
|
|
uint32 type : 4;
|
|
uint32 desc_type : 1;
|
|
uint32 dpl : 2;
|
|
uint32 present : 1;
|
|
uint32 limit1 : 4;
|
|
uint32 available : 1;
|
|
uint32 unused1 : 2;
|
|
uint32 granularity : 1;
|
|
uint32 base1 : 8;
|
|
uint32 base2 : 32;
|
|
uint32 unused2 : 32;
|
|
} _PACKED;
|
|
|
|
// Structure of an interrupt descriptor.
|
|
struct interrupt_descriptor {
|
|
uint32 base0 : 16;
|
|
uint32 sel : 16;
|
|
uint32 ist : 3;
|
|
uint32 unused1 : 5;
|
|
uint32 type : 4;
|
|
uint32 unused2 : 1;
|
|
uint32 dpl : 2;
|
|
uint32 present : 1;
|
|
uint32 base1 : 16;
|
|
uint32 base2 : 32;
|
|
uint32 reserved : 32;
|
|
} _PACKED;
|
|
|
|
struct gdt_idt_descr {
|
|
uint16 limit;
|
|
addr_t base;
|
|
} _PACKED;
|
|
|
|
struct tss {
|
|
uint32 _reserved1;
|
|
uint64 sp0;
|
|
uint64 sp1;
|
|
uint64 sp2;
|
|
uint64 _reserved2;
|
|
uint64 ist1;
|
|
uint64 ist2;
|
|
uint64 ist3;
|
|
uint64 ist4;
|
|
uint64 ist5;
|
|
uint64 ist6;
|
|
uint64 ist7;
|
|
uint64 _reserved3;
|
|
uint16 _reserved4;
|
|
uint16 io_map_base;
|
|
} _PACKED;
|
|
|
|
|
|
static inline void
|
|
clear_segment_descriptor(segment_descriptor* desc)
|
|
{
|
|
*(uint64*)desc = 0;
|
|
}
|
|
|
|
|
|
static inline void
|
|
set_segment_descriptor(segment_descriptor* desc, uint8 type, uint8 dpl)
|
|
{
|
|
clear_segment_descriptor(desc);
|
|
|
|
// In 64-bit mode the CPU ignores the base/limit of code/data segments,
|
|
// it always treats base as 0 and does no limit checks.
|
|
desc->base0 = 0;
|
|
desc->base1 = 0;
|
|
desc->limit0 = 0xffff;
|
|
desc->limit1 = 0xf;
|
|
desc->granularity = 1;
|
|
|
|
desc->type = type;
|
|
desc->desc_type = DT_CODE_DATA_SEGMENT;
|
|
desc->dpl = dpl;
|
|
desc->present = 1;
|
|
|
|
desc->long_mode = (type & DT_CODE_EXECUTE_ONLY) ? 1 : 0;
|
|
// Must be set to 1 for code segments only.
|
|
}
|
|
|
|
|
|
static inline void
|
|
set_tss_descriptor(segment_descriptor* _desc, uint64 base, uint32 limit)
|
|
{
|
|
clear_segment_descriptor(_desc);
|
|
clear_segment_descriptor(&_desc[1]);
|
|
|
|
// The TSS descriptor is a special format in 64-bit mode, it is 16 bytes
|
|
// instead of 8.
|
|
tss_descriptor* desc = (tss_descriptor*)_desc;
|
|
|
|
desc->base0 = base & 0xffffff;
|
|
desc->base1 = (base >> 24) & 0xff;
|
|
desc->base2 = (base >> 32);
|
|
desc->limit0 = limit & 0xffff;
|
|
desc->limit1 = (limit >> 16) & 0xf;
|
|
|
|
desc->present = 1;
|
|
desc->type = DT_TSS;
|
|
desc->desc_type = DT_SYSTEM_SEGMENT;
|
|
desc->dpl = DPL_KERNEL;
|
|
}
|
|
|
|
|
|
static inline void
|
|
set_interrupt_descriptor(interrupt_descriptor* desc, uint64 addr, uint32 type,
|
|
uint16 seg, uint32 dpl, uint32 ist)
|
|
{
|
|
desc->base0 = addr & 0xffff;
|
|
desc->base1 = (addr >> 16) & 0xffff;
|
|
desc->base2 = (addr >> 32) & 0xffffffff;
|
|
desc->sel = seg;
|
|
desc->ist = ist;
|
|
desc->type = type;
|
|
desc->dpl = dpl;
|
|
desc->present = 1;
|
|
desc->unused1 = 0;
|
|
desc->unused2 = 0;
|
|
desc->reserved = 0;
|
|
}
|
|
|
|
|
|
#endif /* _ASSEMBLER */
|
|
|
|
#endif /* _KERNEL_ARCH_X86_64_DESCRIPTORS_H */
|