diff --git a/arch/x86/tools/.gitignore b/arch/x86/tools/.gitignore new file mode 100644 index 0000000..5ac19b6 --- /dev/null +++ b/arch/x86/tools/.gitignore @@ -0,0 +1 @@ +./gdt diff --git a/arch/x86/tools/gdt.c b/arch/x86/tools/gdt.c new file mode 100644 index 0000000..cc97aed --- /dev/null +++ b/arch/x86/tools/gdt.c @@ -0,0 +1,134 @@ +/* + * This program generates the GDT entries for the x86. + * Taken from <https://wiki.osdev.org/GDT_Tutorial> and modified to our needs. + * It conforms to ISO C99 and can be built on any POSIX compliant system using + * the command `make gdt.c`. It outputs the assembly directives for the GDT. + * + * May nobody need to touch this mess ever again. + */ + +#include <assert.h> +#include <inttypes.h> +#include <stdint.h> +#include <stdio.h> + +/* + * Each define here is for a specific flag in the descriptor. + * See the Intel SDM vol 3A, sec 3.4, fig 3-8 for details. + */ +#define SEG_TYPE(x) ((x) << 12) /* Descriptor type (0 for system, 1 for code/data) */ +#define SEG_PRIV(x) (((x) & 3) << 13) /* Descriptor Privilege Level (0 - 3) */ +#define SEG_PRES(x) ((x) << 15) /* Present */ +#define SEG_AVL(x) ((x) << 20) /* Available for system use (we don't use that) */ +#define SEG_LONG(x) ((x) << 21) /* 64-bit Long mode code segment */ +#define SEG_SIZE(x) ((x) << 22) /* Size (0 for 16/64-bit, 1 for 32) */ +#define SEG_GRAN(x) ((x) << 23) /* Granularity (0 for 1B - 1MB, 1 for 4KB - 4GB) */ + +#define SEG_DATA_R 0x000 /* read */ +#define SEG_DATA_RA 0x100 /* read, accessed */ +#define SEG_DATA_RW 0x200 /* read, write */ +#define SEG_DATA_RWA 0x300 /* read, write, accessed */ +#define SEG_DATA_RE 0x400 /* read, expand-down */ +#define SEG_DATA_REA 0x500 /* read, expand-down, accessed */ +#define SEG_DATA_REW 0x600 /* read, write */ +#define SEG_DATA_REWA 0x700 /* read, expand-down, write, accessed */ + +#define SEG_CODE_X 0x800 /* execute */ +#define SEG_CODE_XA 0x900 /* execute, accessed */ +#define SEG_CODE_XR 0xa00 /* execute, read */ +#define SEG_CODE_XRA 0xb00 /* execute, read, accessed */ +#define SEG_CODE_XC 0xc00 /* execute, conforming */ +#define SEG_CODE_XCA 0xd00 /* execute, conforming, accessed */ +#define SEG_CODE_XCR 0xe00 /* execute, conforming, read */ +#define SEG_CODE_XCRA 0xf00 /* execute, conforming, read, accessed */ + +#define KERN_CODE32 ( \ + SEG_TYPE(1) | SEG_PRES(1) | SEG_AVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ + SEG_PRIV(0) | SEG_CODE_XR \ +) + +#define USER_CODE32 ( \ + SEG_TYPE(1) | SEG_PRES(1) | SEG_AVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ + SEG_PRIV(3) | SEG_CODE_XR \ +) + +#define KERN_CODE64 ( \ + SEG_TYPE(1) | SEG_PRES(1) | SEG_AVL(0) | \ + SEG_LONG(1) | SEG_SIZE(0) | SEG_GRAN(1) | \ + SEG_PRIV(0) | SEG_CODE_XR \ +) + +#define USER_CODE64 ( \ + SEG_TYPE(1) | SEG_PRES(1) | SEG_AVL(0) | \ + SEG_LONG(1) | SEG_SIZE(0) | SEG_GRAN(1) | \ + SEG_PRIV(3) | SEG_CODE_XR \ +) + +#define KERN_DATA ( \ + SEG_TYPE(1) | SEG_PRES(1) | SEG_AVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ + SEG_PRIV(0) | SEG_DATA_RW \ +) + +#define USER_DATA ( \ + SEG_TYPE(1) | SEG_PRES(1) | SEG_AVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ + SEG_PRIV(3) | SEG_DATA_RW \ +) + +#define KERN_TSS ( \ + SEG_TYPE(0) | SEG_PRES(1) | SEG_AVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(0) | \ + SEG_PRIV(0) | SEG_CODE_XA \ +) + +#define USER_TSS ( \ + SEG_TYPE(0) | SEG_PRES(1) | SEG_AVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(0) | \ + SEG_PRIV(3) | SEG_CODE_XA \ +) + +int offset(void) +{ + static int i = 0; + return i++ * 8; +} + +void print_desc(uint32_t base, uint32_t limit, uint32_t flag, const char *comment) +{ + uint32_t low_desc, high_desc; + + /* Create the low 32 bit segment part */ + low_desc = base << 16; /* set base bits 15:0 */ + low_desc |= limit & 0x0000FFFF; /* set limit bits 15:0 */ + + /* Create the high 32 bit segment part */ + high_desc = limit & 0x000F0000; /* set limit bits 19:16 */ + high_desc |= flag & 0x00F0FF00; /* set type, p, dpl, s, g, d/b, l and avl fields */ + high_desc |= (base >> 16) & 0x000000FF; /* set base bits 23:16 */ + high_desc |= base & 0xFF000000; /* set base bits 31:24 */ + + printf("\t.quad 0x%08"PRIx32"%08"PRIx32" /* 0x%02x %s */\n", + high_desc, low_desc, offset(), comment); +} + +int main(void) +{ + print_desc(0, 0x00000000, 0, "null descriptor "); + print_desc(0, 0x00000000, 0, "unused "); + print_desc(0, 0x000fffff, KERN_CODE32, "kernel code 32-bit"); + print_desc(0, 0x000fffff, USER_CODE32, "user code 32-bit"); + print_desc(0, 0x000fffff, KERN_CODE64, "kernel code 64-bit"); + print_desc(0, 0x000fffff, USER_CODE64, "user code 64-bit"); + print_desc(0, 0x000fffff, KERN_DATA, "kernel data "); + print_desc(0, 0x000fffff, USER_DATA, "user data "); + /* the TSS bases are initialized dynamically in arch/x86/boot/setup{32,64}.S */ + print_desc(0, 0x00000068, KERN_TSS, "kernel TSS "); + print_desc(0, 0x00000000, 0, " .. pad for 64-bit"); + print_desc(0, 0x00000068, USER_TSS, "user TSS "); + print_desc(0, 0x00000000, 0, " .. pad for 64-bit"); + + return 0; +}