diff options
author | Danny Holman <dholman@gymli.xyz> | 2021-07-24 02:27:40 -0500 |
---|---|---|
committer | Danny Holman <dholman@gymli.xyz> | 2021-07-24 02:27:40 -0500 |
commit | 7498b41d94b2f34468833b55ad0472d75b63064e (patch) | |
tree | a16b9c728edd4116b401f7fd337cb36b8d33fd78 /arch | |
parent | d4003f1d6daf6883acb83a398e3fdba5336aefef (diff) |
arch: i386: add GDT setup routines
Add a set of routines that setup the x86's global descriptor table.
Signed-off-by: Danny Holman <dholman@gymli.xyz>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/i386/boot/boot.s | 18 | ||||
-rw-r--r-- | arch/i386/boot/gdt.c | 79 | ||||
-rw-r--r-- | arch/i386/include/gdt.h | 69 | ||||
-rw-r--r-- | arch/i386/make.config | 1 |
4 files changed, 98 insertions, 69 deletions
diff --git a/arch/i386/boot/boot.s b/arch/i386/boot/boot.s index 792a790..842519f 100644 --- a/arch/i386/boot/boot.s +++ b/arch/i386/boot/boot.s @@ -68,8 +68,26 @@ _start: movl $stack_top, %esp + call tty_init + call gdt_install call kernel_main cli 1: hlt jmp 1b + +.global flush_gdt +.type flush_gdt, @function + +flush_gdt: + cli + movl 4(%esp), %eax + lgdt (%eax) + movw $0x10, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + jmp $0x08, $.flush +.flush: ret diff --git a/arch/i386/boot/gdt.c b/arch/i386/boot/gdt.c new file mode 100644 index 0000000..d9bfc1e --- /dev/null +++ b/arch/i386/boot/gdt.c @@ -0,0 +1,79 @@ +#include <kernel/io.h> +#include <stdint.h> + +#define SEG_DESCTYPE(x) ((x) << 0x04) // Descriptor type (0 for system, 1 for code/data) +#define SEG_PRES(x) ((x) << 0x07) // Present +#define SEG_SAVL(x) ((x) << 0x0C) // Available for system use +#define SEG_LONG(x) ((x) << 0x0D) // Long mode +#define SEG_SIZE(x) ((x) << 0x0E) // Size (0 for 16-bit, 1 for 32) +#define SEG_GRAN(x) ((x) << 0x0F) // Granularity (0 for 1B - 1MB, 1 for 4KB - 4GB) +#define SEG_PRIV(x) (((x) & 0x03) << 0x05) // Set privilege level (0 - 3) + +#define SEG_DATA_RD 0x00 // Read-Only +#define SEG_DATA_RDA 0x01 // Read-Only, accessed +#define SEG_DATA_RDWR 0x02 // Read/Write +#define SEG_DATA_RDWRA 0x03 // Read/Write, accessed +#define SEG_DATA_RDEXPD 0x04 // Read-Only, expand-down +#define SEG_DATA_RDEXPDA 0x05 // Read-Only, expand-down, accessed +#define SEG_DATA_RDWREXPD 0x06 // Read/Write, expand-down +#define SEG_DATA_RDWREXPDA 0x07 // Read/Write, expand-down, accessed +#define SEG_CODE_EX 0x08 // Execute-Only +#define SEG_CODE_EXA 0x09 // Execute-Only, accessed +#define SEG_CODE_EXRD 0x0A // Execute/Read +#define SEG_CODE_EXRDA 0x0B // Execute/Read, accessed +#define SEG_CODE_EXC 0x0C // Execute-Only, conforming +#define SEG_CODE_EXCA 0x0D // Execute-Only, conforming, accessed +#define SEG_CODE_EXRDC 0x0E // Execute/Read, conforming +#define SEG_CODE_EXRDCA 0x0F // Execute/Read, conforming, accessed + +#define GDT_CODE_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ + SEG_PRIV(0) | SEG_CODE_EXRD + +#define GDT_DATA_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ + SEG_PRIV(0) | SEG_DATA_RDWR + +#define GDT_CODE_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ + SEG_PRIV(3) | SEG_CODE_EXRD + +#define GDT_DATA_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ + SEG_PRIV(3) | SEG_DATA_RDWR + +struct gpt_ptr { + uint16_t limit; + uint32_t base; +}__attribute__((packed)); + +uint64_t desc[3]; +struct gpt_ptr gp; + +extern void flush_gdt(struct gpt_ptr *ptr); + +uint64_t create_gdt_entry(uint32_t base, uint32_t limit, uint16_t flag) { + uint64_t ret; + + ret = limit & 0x000F0000; + ret |= (flag << 8) & 0x00F0FF00; + ret |= (base >> 16) & 0x000000FF; + ret |= base & 0xFF000000; + + ret <<= 32; + + ret |= base << 16; + ret |= limit & 0x0000FFFF; + + return ret; +} + +void gdt_install(void) { + gp.limit = 64 * 3 - 1; + gp.base = (uint32_t)&desc; + + desc[0] = create_gdt_entry(0, 0, 0); + desc[1] = create_gdt_entry(0, 0x000FFFFF, (GDT_CODE_PL0)); + desc[2] = create_gdt_entry(0, 0x000FFFFF, (GDT_DATA_PL0)); + flush_gdt(&gp); +} diff --git a/arch/i386/include/gdt.h b/arch/i386/include/gdt.h deleted file mode 100644 index 4ffa155..0000000 --- a/arch/i386/include/gdt.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef GDT_H -#define GDT_H - -#include <stdint.h> - -#define SEG_DESCTYPE(x) ((x) << 0x04) -#define SEG_PRES(x) ((x) << 0x07) -#define SEG_SAVL(x) ((x) << 0x0C) -#define SEG_LONG(x) ((x) << 0x0D) -#define SEG_SIZE(x) ((x) << 0x0E) -#define SEG_GRAN(x) ((x) << 0x0F) -#define SEG_PRIV(x) (((x) & 0x03) << 0x05) - -#define SEG_DATA_RD 0x00 -#define SEG_DATA_RDA 0x01 -#define SEG_DATA_RDWR 0x02 -#define SEG_DATA_RDWRA 0x03 -#define SEG_DATA_RDEXPD 0x04 -#define SEG_DATA_RDEXPDA 0x05 -#define SEG_DATA_RDWREXD 0x06 -#define SEG_DATA_RDWREXDA 0x07 -#define SEG_CODE_EX 0x08 -#define SEG_CODE_EXA 0x09 -#define SEG_CODE_EXRD 0x0A -#define SEG_CODE_EXRDA 0x0B -#define SEG_CODE_EXC 0x0C -#define SEG_CODE_EXCA 0x0D -#define SEG_CODE_EXRDC 0x0E -#define SEG_CODE_EXRDCA 0x0F - -#define GDT_CODE_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \ - SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ - SEG_PRIV(0) | SEG_CODE_EXRD - -#define GDT_DATA_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \ - SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ - SEG_PRIV(0) | SEG_CODE_RDWR - -#define GDT_CODE_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \ - SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ - SEG_PRIV(3) | SEG_DATA_EXRD - -#define GDT_DATA_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \ - SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ - SEG_PRIV(3) | SEG_DATA_RDWR - -struct gdt { - uint16_t size; - uint32_t offset; -} __attribute__((packed)); - -void flush_gdt(void); - -uint64_t create_descriptor(uint32_t base, uint32_t limit, uint16_t flag) { - uint64_t descriptor; - - descriptor = limit & 0x000F0000; - descriptor |= (flag << 8) & 0x00F0FF00; - descriptor |= (base >> 16) & 0x000000FF; - descriptor |= base & 0xFF000000; - - descriptor <<= 32; - descriptor |= base << 16; - descriptor |= limit & 0x0000FFFF; - - return descriptor; -} - -#endif diff --git a/arch/i386/make.config b/arch/i386/make.config index 1f09aea..6582794 100644 --- a/arch/i386/make.config +++ b/arch/i386/make.config @@ -5,4 +5,5 @@ KERNEL_ARCH_LIBS= KERNEL_ARCH_OBJS=$(ARCHDIR)/boot/boot.o \ $(ARCHDIR)/boot/tty.o \ + $(ARCHDIR)/boot/gdt.o \ $(ARCHDIR)/kernel/serial.o \ |