You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

135 lines
4.9 KiB
C

/*
* 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;
}