summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/i386/boot/boot.s38
-rw-r--r--arch/i386/boot/gdt.c141
-rw-r--r--arch/i386/boot/tss.c26
-rw-r--r--arch/i386/boot/tss.h39
4 files changed, 176 insertions, 68 deletions
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 <kernel/string.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 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 <kernel/string.h>
+
+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 <stdint.h>
+
+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