diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/amd64/amd64/gdt.c | 76 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/machdep.c | 8 | ||||
-rw-r--r-- | sys/include/arch/amd64/gdt.h | 69 |
3 files changed, 100 insertions, 53 deletions
diff --git a/sys/arch/amd64/amd64/gdt.c b/sys/arch/amd64/amd64/gdt.c index a8fe54d..40d8f48 100644 --- a/sys/arch/amd64/amd64/gdt.c +++ b/sys/arch/amd64/amd64/gdt.c @@ -29,50 +29,70 @@ #include <machine/gdt.h> -struct gdt_entry g_gdt_data[256] = { +/* + * The GDT should be cache line aligned, since it is accessed every time a + * segment selector is reloaded + */ +__cacheline_aligned struct gdt_entry g_gdt_data[GDT_ENTRY_COUNT] = { /* Null */ {0}, - /* Kernel code (0x8) */ + /* Kernel code (0x08) */ { - .limit = 0x0000, - .base_low = 0x0000, - .base_mid = 0x00, - .access = 0x9A, - .granularity = 0x20, - .base_hi = 0x00 + .limit = 0x0000, + .base_low = 0x0000, + .base_mid = 0x00, + .attributes = GDT_ATTRIBUTE_64BIT_CODE | GDT_ATTRIBUTE_PRESENT | + GDT_ATTRIBUTE_DPL0 | GDT_ATTRIBUTE_NONSYSTEM | + GDT_ATTRIBUTE_EXECUTABLE | GDT_ATTRIBUTE_READABLE, + .base_hi = 0x00 }, /* Kernel data (0x10) */ { - .limit = 0x0000, - .base_low = 0x0000, - .base_mid = 0x00, - .access = 0x92, - .granularity = 0x00, - .base_hi = 0x00 + .limit = 0x0000, + .base_low = 0x0000, + .base_mid = 0x00, + .attributes = GDT_ATTRIBUTE_PRESENT | GDT_ATTRIBUTE_DPL0 | + GDT_ATTRIBUTE_NONSYSTEM | GDT_ATTRIBUTE_WRITABLE, + .base_hi = 0x00 }, /* User code (0x18) */ { - .limit = 0x0000, - .base_low = 0x0000, - .base_mid = 0x00, - .access = 0xFA, - .granularity = 0xAF, - .base_hi = 0x00 + .limit = 0x0000, + .base_low = 0x0000, + .base_mid = 0x00, + .attributes = GDT_ATTRIBUTE_64BIT_CODE | GDT_ATTRIBUTE_PRESENT | + GDT_ATTRIBUTE_DPL3 | GDT_ATTRIBUTE_NONSYSTEM | + GDT_ATTRIBUTE_EXECUTABLE | GDT_ATTRIBUTE_READABLE, + .base_hi = 0x00 }, /* User data (0x20) */ { - .limit = 0x0000, - .base_low = 0x0000, - .base_mid = 0x00, - .access = 0xF2, - .granularity = 0x00, - .base_hi = 0x00 + .limit = 0x0000, + .base_low = 0x0000, + .base_mid = 0x00, + .attributes = GDT_ATTRIBUTE_PRESENT | GDT_ATTRIBUTE_DPL3 | + GDT_ATTRIBUTE_NONSYSTEM | GDT_ATTRIBUTE_WRITABLE, + .base_hi = 0x00 }, - /* TSS segment (0x28) */ - {0} + /* + * TSS segment (0x28) + * + * NOTE: 64-bit TSS descriptors are 16 bytes, equivalent to the size of two + * regular descriptor entries. + * See Intel SPG 3/25 Section 9.2.3 - TSS Descriptor in 64-bit mode. + */ + {0}, {0} +}; + +/* Verify that the GDT is of the correct size */ +__static_assert(sizeof(g_gdt_data) == (8 * GDT_ENTRY_COUNT)); + +const struct gdtr g_gdtr = { + .limit = sizeof(g_gdt_data) - 1, + .offset = (uintptr_t)&g_gdt_data[0] }; diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c index da6e554..3381437 100644 --- a/sys/arch/amd64/amd64/machdep.c +++ b/sys/arch/amd64/amd64/machdep.c @@ -59,10 +59,6 @@ void syscall_isr(void); void pin_isr_load(void); struct cpu_info g_bsp_ci = {0}; -static struct gdtr bsp_gdtr = { - .limit = sizeof(struct gdt_entry) * 256 - 1, - .offset = (uintptr_t)&g_gdt_data[0] -}; __attribute__((__interrupt__)) static void @@ -97,7 +93,7 @@ init_tss(struct cpu_info *ci) { struct tss_desc *desc; - desc = (struct tss_desc *)&g_gdt_data[GDT_TSS]; + desc = (struct tss_desc *)&g_gdt_data[GDT_TSS_INDEX]; write_tss(ci, desc); tss_load(); } @@ -239,7 +235,7 @@ void cpu_startup(struct cpu_info *ci) { ci->self = ci; - gdt_load(&bsp_gdtr); + gdt_load(); idt_load(); setup_vectors(); diff --git a/sys/include/arch/amd64/gdt.h b/sys/include/arch/amd64/gdt.h index 55666a7..0c5faf1 100644 --- a/sys/include/arch/amd64/gdt.h +++ b/sys/include/arch/amd64/gdt.h @@ -4,18 +4,48 @@ #include <sys/types.h> #include <sys/cdefs.h> +#define GDT_TSS_INDEX 5 +#define GDT_ENTRY_COUNT 7 + +/* Segment selectors */ #define KERNEL_CS 0x08 #define KERNEL_DS 0x10 -#define USER_CS 0x18 -#define USER_DS 0x20 -#define GDT_TSS 5 +#define USER_CS 0x18 +#define USER_DS 0x20 + +/* + * Bit definitions for regular segment descriptors + * + * See Intel SPG 3/25 Section 3.4.5 - Segment Descriptors + */ + +#define GDT_ATTRIBUTE_ACCESSED BIT(0) /* Accessed */ +#define GDT_ATTRIBUTE_EXECUTABLE BIT(3) /* Executable */ +#define GDT_ATTRIBUTE_NONSYSTEM BIT(4) /* Code/data */ +#define GDT_ATTRIBUTE_PRESENT BIT(7) /* Present */ +#define GDT_ATTRIBUTE_64BIT_CODE BIT(13) /* 64-bit code */ +#define GDT_ATTRIBUTE_32BIT BIT(14) /* 32-bit code/data */ +#define GDT_ATTRIBUTE_GRANULARITY BIT(15) /* 4KiB limit granularity */ + +/* Attributes for executable segments */ +#define GDT_ATTRIBUTE_READABLE BIT(1) /* Readable */ +#define GDT_ATTRIBUTE_CONFORMING BIT(2) /* Conforming */ + +/* Attributes for non-executable segments */ +#define GDT_ATTRIBUTE_WRITABLE BIT(1) /* Writable */ +#define GDT_ATTRIBUTE_EXPANDS_DOWN BIT(2) /* See SPG 3/25 Section 6.8.1 */ + +/* DPL (Descriptor Privilege Level) specifier */ +#define GDT_ATTRIBUTE_DPL0 0 +#define GDT_ATTRIBUTE_DPL1 (1 << 5) +#define GDT_ATTRIBUTE_DPL2 (2 << 5) +#define GDT_ATTRIBUTE_DPL3 (3 << 5) struct __packed gdt_entry { uint16_t limit; uint16_t base_low; uint8_t base_mid; - uint8_t access; - uint8_t granularity; + uint16_t attributes; uint8_t base_hi; }; @@ -24,27 +54,28 @@ struct __packed gdtr { uintptr_t offset; }; +extern struct gdt_entry g_gdt_data[GDT_ENTRY_COUNT]; +extern const struct gdtr g_gdtr; + __always_inline static inline void -gdt_load(struct gdtr *gdtr) +gdt_load(void) { __ASMV("lgdt %0\n" - "push $8\n" /* Push CS */ - "lea 1f(%%rip), %%rax\n" /* Load 1 label address into RAX */ - "push %%rax\n" /* Push the return address (label 1) */ - "lretq\n" /* Far return to update CS */ + "push %1\n" /* Push code segment selector */ + "lea 1f(%%rip), %%rax\n" /* Load label 1 address into RAX */ + "push %%rax\n" /* Push return address (label 1) */ + "lretq\n" /* Far return to update CS */ "1:\n" - " mov $0x10, %%eax\n" - " mov %%eax, %%ds\n" - " mov %%eax, %%es\n" - " mov %%eax, %%fs\n" - " mov %%eax, %%gs\n" - " mov %%eax, %%ss\n" + " mov %2, %%ax\n" /* Load data segment selectors */ + " mov %%ax, %%ds\n" + " mov %%ax, %%es\n" + " mov %%ax, %%fs\n" + " mov %%ax, %%gs\n" + " mov %%ax, %%ss\n" : - : "m" (*gdtr) + : "m" (g_gdtr), "i"(KERNEL_CS), "i"(KERNEL_DS) : "rax", "memory" ); } -extern struct gdt_entry g_gdt_data[256]; - #endif /* !AMD64_GDT_H_ */ |