From acc73186bc3de78ceb0a54cbf2605dff1b9a6d62 Mon Sep 17 00:00:00 2001 From: Danny Holman Date: Sat, 15 Jan 2022 16:20:52 -0600 Subject: arch: i386: simplifiy GDT setup Simplify the setup and definitions of GDT/TSS entries. Signed-off-by: Danny Holman --- arch/i386/boot/boot.s | 38 ++++++++++++-- arch/i386/boot/gdt.c | 141 ++++++++++++++++++++++++++++---------------------- arch/i386/boot/tss.c | 26 ++++++++++ arch/i386/boot/tss.h | 39 ++++++++++++++ 4 files changed, 176 insertions(+), 68 deletions(-) create mode 100644 arch/i386/boot/tss.c create mode 100644 arch/i386/boot/tss.h (limited to 'arch/i386') diff --git a/arch/i386/boot/boot.s b/arch/i386/boot/boot.s index c62abbf..4b32ca2 100644 --- a/arch/i386/boot/boot.s +++ b/arch/i386/boot/boot.s @@ -25,7 +25,6 @@ boot_page_table0: .section .multiboot.text, "a" .global _start .type _start, @function - _start: movl $(boot_page_table0 - 0xC0000000), %edi movl $0, %esi @@ -73,6 +72,7 @@ _start: call pic_remap call kernel_main + call jump_userspace cli 1: hlt @@ -80,11 +80,9 @@ _start: .global flush_gdt .type flush_gdt, @function - flush_gdt: cli - movl 4(%esp), %eax - lgdt (%eax) + lgdt (gp) movw $0x10, %ax movw %ax, %ds movw %ax, %es @@ -92,4 +90,34 @@ flush_gdt: movw %ax, %gs movw %ax, %ss jmp $0x08, $.flush -.flush: ret +.flush: + ret + +.global flush_tss +.type flush_tss, @function +flush_tss: + movw $0x28, %ax + ltr %ax + ret + +.global jump_userspace +.type jump_userspace, @function +jump_userspace: + cli + movw $0x23, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + + pushl $0x23 + pushl %esp + pushf + orl $0x200, (%esp) + pushl $0x8 + pushl $test_user_function + iret + +test_user_function: + movl $1, %eax + int $0x80 diff --git a/arch/i386/boot/gdt.c b/arch/i386/boot/gdt.c index 6552721..3972e53 100644 --- a/arch/i386/boot/gdt.c +++ b/arch/i386/boot/gdt.c @@ -1,80 +1,95 @@ +#include #include -#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 gdt_entry { + uint16_t limit_low; + uint16_t base_low; + uint8_t base_middle; + uint8_t access; + uint8_t gran; + uint8_t base_high; +} __attribute__((packed)); -struct gpt_ptr { +struct gdt_ptr { uint16_t limit; uint32_t base; -}__attribute__((packed)); +} __attribute__((packed)); -uint64_t gdt_desc[5]; -struct gpt_ptr gp; +struct tss_entry { + uint32_t link; + uint32_t esp0; + uint32_t ss0; + uint32_t esp1; + uint32_t ss2; + uint32_t cr3; + uint32_t eip; + uint32_t eflags; + uint32_t eax; + uint32_t ecx; + uint32_t edx; + uint32_t ebx; + uint32_t esp; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint32_t es; + uint32_t cs; + uint32_t ss; + uint32_t ds; + uint32_t fs; + uint32_t gs; + uint32_t ldtr; + uint16_t trap; + uint16_t iomap_base; +} __attribute__((packed)); -extern void flush_gdt(struct gpt_ptr *ptr); +struct gdt_entry desc[6]; +struct gdt_ptr gp; +struct tss_entry tss_entry; -uint64_t create_gdt_entry(uint32_t base, uint32_t limit, uint16_t flag) { - uint64_t ret; +extern void flush_gdt(void); +extern void flush_tss(void); - ret = limit & 0x000F0000; - ret |= (flag << 8) & 0x00F0FF00; - ret |= (base >> 16) & 0x000000FF; - ret |= base & 0xFF000000; +void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) { + desc[num].base_low = (base & 0xFFFF); + desc[num].base_middle = (base >> 16) & 0xFF; + desc[num].base_high = (base >> 24) & 0xFF; - ret <<= 32; + desc[num].limit_low = (limit & 0xFFFF); + desc[num].gran = (limit >> 16) & 0x0F; + desc[num].gran |= (gran & 0xF0); + desc[num].access = access; +} - ret |= base << 16; - ret |= limit & 0x0000FFFF; +void write_tss(int num, uint16_t ss0, uint16_t esp0) { + uint32_t base = (uint32_t)&tss_entry; + uint32_t limit = base + sizeof(tss_entry); - return ret; + gdt_set_gate(num, base, limit, 0xE9, 0x00); + memset(&tss_entry, 0x0, sizeof(tss_entry)); + + tss_entry.ss0 = ss0; + tss_entry.esp0 = esp0; + tss_entry.cs = 0x0B; + tss_entry.ss = 0x13; + tss_entry.ds = 0x13; + tss_entry.es = 0x13; + tss_entry.fs = 0x13; + tss_entry.gs = 0x13; + tss_entry.iomap_base = sizeof(tss_entry); } void gdt_install(void) { - gp.limit = 64 * 5 - 1; - gp.base = (uint32_t)&gdt_desc; + gp.limit = (sizeof(struct gdt_entry) * 6) - 1; + gp.base = (uint32_t)&desc; + + gdt_set_gate(0, 0, 0, 0, 0); + gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); + gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); + gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); + gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); + write_tss(5, 0x10, 0x0); - gdt_desc[0] = create_gdt_entry(0, 0, 0); - gdt_desc[1] = create_gdt_entry(0, 0x000FFFFF, GDT_CODE_PL0); - gdt_desc[2] = create_gdt_entry(0, 0x000FFFFF, GDT_DATA_PL0); - gdt_desc[3] = create_gdt_entry(0, 0x000FFFFF, GDT_DATA_PL3); - gdt_desc[4] = create_gdt_entry(0, 0x000FFFFF, GDT_DATA_PL3); - flush_gdt(&gp); + flush_gdt(); + flush_tss(); } diff --git a/arch/i386/boot/tss.c b/arch/i386/boot/tss.c new file mode 100644 index 0000000..2edfa76 --- /dev/null +++ b/arch/i386/boot/tss.c @@ -0,0 +1,26 @@ +#include "tss.h" +#include + +struct tss tss_entry; + +uint64_t create_tss_entry(uint16_t ss0, uint32_t esp0) { + uint32_t base = (uint32_t)&tss_entry; + uint32_t limit = base + sizeof(&tss_entry); + uint64_t ret = create_gdt_entry(base, limit, 0xE9); + + memset(&tss_entry, 0, sizeof(struct tss)); + tss_entry.ss0 = ss0; + tss_entry.esp0 = esp0; + tss_entry.cs = 0x08; + tss_entry.ss = 0x13; + tss_entry.ds = 0x13; + tss_entry.es = 0x13; + tss_entry.fs = 0x13; + tss_entry.gs = 0x13; + tss_entry.io_offset = sizeof(struct tss) & 0xFFFF; + return ret; +} + +void set_kernel_stack(uint32_t stack) { + tss_entry.esp0 = stack; +} diff --git a/arch/i386/boot/tss.h b/arch/i386/boot/tss.h new file mode 100644 index 0000000..28bae6e --- /dev/null +++ b/arch/i386/boot/tss.h @@ -0,0 +1,39 @@ +#ifndef I386_TSS_H +#define I386_TSS_H + +#include + +struct tss { + uint32_t link; + uint32_t esp0; + uint32_t ss0; + uint32_t esp1; + uint32_t ss2; + uint32_t cr3; + uint32_t eip; + uint32_t eflags; + uint32_t eax; + uint32_t ecx; + uint32_t edx; + uint32_t ebx; + uint32_t esp; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint32_t es; + uint32_t cs; + uint32_t ss; + uint32_t ds; + uint32_t fs; + uint32_t gs; + uint32_t ldtr; + uint32_t io_offset; +}__attribute__((packed)); + +void flush_tss(void); + +uint64_t create_gdt_entry(uint32_t base, uint32_t limit, uint16_t flag); +uint64_t create_tss_entry(uint16_t ss0, uint32_t esp0); +void set_kernel_stack(uint32_t stack); + +#endif -- cgit v1.2.3