diff --git a/sortix/Makefile b/sortix/Makefile
index 0fbf63da..8645d9cb 100644
--- a/sortix/Makefile
+++ b/sortix/Makefile
@@ -46,7 +46,6 @@ ifdef X86FAMILY
$(CPU)/memorymanagement.o \
x86-family/memorymanagement.o \
$(CPU)/interrupt.o \
- $(CPU)/gdt.o \
x86-family/gdt.o \
x86-family/idt.o \
$(CPU)/syscall.o \
diff --git a/sortix/x64/gdt.s b/sortix/x64/gdt.s
deleted file mode 100644
index 5ad62cf2..00000000
--- a/sortix/x64/gdt.s
+++ /dev/null
@@ -1,64 +0,0 @@
-/*******************************************************************************
-
- Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
-
- This file is part of Sortix.
-
- Sortix is free software: you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation, either version 3 of the License, or (at your option) any later
- version.
-
- Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- Sortix. If not, see .
-
- x64/gdt.s
- Handles initialization of the 64-bit global descriptor table.
-
-*******************************************************************************/
-
-.section .text
-
-.global gdt_flush
-.type gdt_flush, @function
-gdt_flush:
- # Load the new GDT pointer
- lgdtq (%rdi)
-
- # 0x10 is the offset in the GDT to our data segment
- mov $0x10, %ax
- mov %ax, %ds
- mov %ax, %es
- mov %ax, %fs
- mov %ax, %gs
- mov %ax, %ss
-
- # Far jump to our new code segment!
- movq $GDT_FLUSH_POSTJMP, %rax
- ljmp *(%rax)
-gdt_flush_postjmp:
- ret
-.size gdt_flush, . - gdt_flush
-
-.global tss_flush
-.type tss_flush, @function
-tss_flush:
- # Load the index of our TSS structure - The index is 0x28, as it is the 5th
- # selector and each is 8 bytes long, but we set the bottom two bits (making
- # 0x2B) so that it has an RPL of 3, not zero.
- mov $0x2B, %ax
-
- # Load the task state register.
- ltr %ax
- ret
-.size tss_flush, . - tss_flush
-
-.section .data
-GDT_FLUSH_POSTJMP:
- .long gdt_flush_postjmp
- .word 0x08 # 0x08 is the offset to our code segment
diff --git a/sortix/x86-family/gdt.cpp b/sortix/x86-family/gdt.cpp
index fa2e0650..a4361b73 100644
--- a/sortix/x86-family/gdt.cpp
+++ b/sortix/x86-family/gdt.cpp
@@ -1,6 +1,6 @@
/*******************************************************************************
- Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
+ Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
This file is part of Sortix.
@@ -22,139 +22,233 @@
*******************************************************************************/
-#include
+#include
#include
+
+#include
+
#include "gdt.h"
-namespace Sortix
+namespace Sortix {
+namespace GDT {
+
+struct gdt_entry
{
- namespace GDT
- {
- extern "C" void gdt_flush(addr_t);
- extern "C" void tss_flush();
+ uint16_t limit_low;
+ uint16_t base_low;
+ uint8_t base_middle;
+ uint8_t access;
+ uint8_t granularity;
+ uint8_t base_high;
+};
- const size_t GDT_NUM_ENTRIES = 7;
- gdt_entry_t gdt_entries[GDT_NUM_ENTRIES];
- gdt_ptr_t gdt_ptr;
- tss_entry_t tss_entry;
+struct gdt_entry64
+{
+ uint16_t limit_low;
+ uint16_t base_low;
+ uint8_t base_middle;
+ uint8_t access;
+ uint8_t granularity;
+ uint8_t base_high;
+ uint32_t base_highest;
+ uint32_t reserved0;
+} __attribute__((packed));
- const uint8_t GRAN_64_BIT_MODE = 1<<5;
- const uint8_t GRAN_32_BIT_MODE = 1<<6;
- const uint8_t GRAN_4KIB_BLOCKS = 1<<7;
-
- void Init()
- {
- gdt_ptr.limit = (sizeof(gdt_entry_t) * GDT_NUM_ENTRIES) - 1;
- gdt_ptr.base = (addr_t) &gdt_entries;
-
-#ifdef PLATFORM_X86
- const uint8_t gran = GRAN_4KIB_BLOCKS | GRAN_32_BIT_MODE;
-#elif defined(PLATFORM_X64)
- const uint8_t gran = GRAN_4KIB_BLOCKS | GRAN_64_BIT_MODE;
-#endif
-
- SetGate(0, 0, 0, 0, 0); // Null segment
- SetGate(1, 0, 0xFFFFFFFF, 0x9A, gran); // Code segment
- SetGate(2, 0, 0xFFFFFFFF, 0x92, gran); // Data segment
- SetGate(3, 0, 0xFFFFFFFF, 0xFA, gran); // User mode code segment
- SetGate(4, 0, 0xFFFFFFFF, 0xF2, gran); // User mode data segment
-
- WriteTSS(5, 0x10, 0x0);
-
- if ( gdt_ptr.base != (addr_t) &gdt_entries )
- {
- // If this happens, then either there is a bug in the GDT entry
- // writing code - or the struct gdt_entries above is too small.
- Panic("Whoops, someone overwrote the GDT pointer while writing "
- "to the GDT entries!");
- }
-
- gdt_flush((addr_t) &gdt_ptr);
- tss_flush();
- }
-
- // Set the value of a GDT entry.
- void SetGate(int32_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran)
- {
- gdt_entry_t* entry = (gdt_entry_t*) (&gdt_entries[num]);
-
- entry->base_low = (base & 0xFFFF);
- entry->base_middle = (base >> 16) & 0xFF;
- entry->base_high = (base >> 24) & 0xFF;
-
- entry->limit_low = (limit & 0xFFFF);
- entry->granularity = ((limit >> 16) & 0x0F) | (gran & 0xF0);
-
- entry->access = access;
- }
-
- // Set the value of a GDT entry.
- void SetGate64(int32_t num, uint64_t base, uint32_t limit, uint8_t access, uint8_t gran)
- {
- gdt_entry64_t* entry = (gdt_entry64_t*) (&gdt_entries[num]);
-
- entry->base_low = (base & 0xFFFF);
- entry->base_middle = (base >> 16) & 0xFF;
- entry->base_high = (base >> 24) & 0xFF;
- entry->base_highest = (base >> 32);
-
- entry->limit_low = (limit & 0xFFFF);
- entry->granularity = ((limit >> 16) & 0x0F) | (gran & 0xF0);
-
- entry->access = access;
- entry->zero1 = 0;
- }
-
- // Initialise our task state segment structure.
- void WriteTSS(int32_t num, uint16_t ss0, addr_t stack0)
- {
- // First, let's compute the base and limit of our entry in the GDT.
- addr_t base = (addr_t) &tss_entry;
- uint32_t limit = base + sizeof(tss_entry);
-
- // Now, add our TSS descriptor's address to the GDT.
-#ifdef PLATFORM_X86
- SetGate(num, base, limit, 0xE9, 0x00);
-#elif defined(PLATFORM_X64)
- SetGate64(num, base, limit, 0xE9, 0x00);
-#endif
-
- // Ensure the descriptor is initially zero.
- memset(&tss_entry, 0, sizeof(tss_entry));
-
-#ifdef PLATFORM_X86
- tss_entry.ss0 = ss0; // Set the kernel stack segment.
- tss_entry.esp0 = stack0; // Set the kernel stack pointer.
-
- // Here we set the cs, ss, ds, es, fs and gs entries in the TSS.
- // These specify what segments should be loaded when the processor
- // switches to kernel mode. Therefore they are just our normal
- // kernel code/data segments - 0x08 and 0x10 respectively, but with
- // the last two bits set, making 0x0b and 0x13. The setting of these
- // bits sets the RPL (requested privilege level) to 3, meaning that
- // this TSS can be used to switch to kernel mode from ring 3.
- tss_entry.cs = 0x08 | 0x3;
- tss_entry.ss = tss_entry.ds = tss_entry.es = tss_entry.fs = tss_entry.gs = 0x10 | 0x3;
-#elif defined(PLATFORM_X64)
- (void) ss0;
- tss_entry.stack0 = stack0;
-#endif
- }
-
- void SetKernelStack(addr_t stacklower, size_t stacksize, addr_t stackhigher)
- {
-#ifdef PLATFORM_X86
- (void) stacklower;
- (void) stacksize;
- tss_entry.esp0 = (uint32_t) stackhigher;
-#elif defined(PLATFORM_X64)
- (void) stacklower;
- (void) stacksize;
- tss_entry.stack0 = (uint64_t) stackhigher;
+struct gdt_ptr
+{
+ uint16_t limit;
+#if defined(__i386__)
+ uint32_t base;
#else
- #warning "TSS is not yet supported on this arch!"
- while(true);
+ uint64_t base;
#endif
- }
- }
+} __attribute__((packed));
+
+#if defined(__i386__)
+struct tss_entry
+{
+ uint32_t prev_tss; // The previous TSS - if we used hardware task switching this would form a linked list.
+ uint32_t esp0; // The stack pointer to load when we change to kernel mode.
+ uint32_t ss0; // The stack segment to load when we change to kernel mode.
+ uint32_t esp1; // Unused...
+ uint32_t ss1;
+ uint32_t esp2;
+ 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; // The value to load into ES when we change to kernel mode.
+ uint32_t cs; // The value to load into CS when we change to kernel mode.
+ uint32_t ss; // The value to load into SS when we change to kernel mode.
+ uint32_t ds; // The value to load into DS when we change to kernel mode.
+ uint32_t fs; // The value to load into FS when we change to kernel mode.
+ uint32_t gs; // The value to load into GS when we change to kernel mode.
+ uint32_t ldt; // Unused...
+ uint16_t trap;
+ uint16_t iomap_base;
+} __attribute__((packed));
+#elif defined(__x86_64__)
+struct tss_entry
+{
+ uint32_t reserved0;
+ uint64_t stack0;
+ uint64_t stack1;
+ uint64_t stack2;
+ uint64_t reserved2;
+ uint64_t ist[7];
+ uint64_t reserved3;
+ uint16_t reserved4;
+ uint16_t iomap_base;
+} __attribute__((packed));
+#endif
+
+const size_t GDT_NUM_ENTRIES = 7;
+static struct gdt_entry gdt_entries[GDT_NUM_ENTRIES];
+
+static struct tss_entry tss_entry;
+
+const uint8_t GRAN_64_BIT_MODE = 1 << 5;
+const uint8_t GRAN_32_BIT_MODE = 1 << 6;
+const uint8_t GRAN_4KIB_BLOCKS = 1 << 7;
+
+void SetGate(int32_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran)
+{
+ struct gdt_entry* entry = (struct gdt_entry*) &gdt_entries[num];
+
+ entry->base_low = base >> 0 & 0xFFFF;
+ entry->base_middle = base >> 16 & 0xFF;
+ entry->base_high = base >> 24 & 0xFF;
+
+ entry->limit_low = limit & 0xFFFF;
+ entry->granularity = (limit >> 16 & 0x0F) | (gran & 0xF0);
+
+ entry->access = access;
}
+
+void SetGate64(int32_t num, uint64_t base, uint32_t limit, uint8_t access, uint8_t gran)
+{
+ struct gdt_entry64* entry = (struct gdt_entry64*) &gdt_entries[num];
+
+ entry->base_low = base >> 0 & 0xFFFF;
+ entry->base_middle = base >> 16 & 0xFF;
+ entry->base_high = base >> 24 & 0xFF;
+ entry->base_highest = base >> 32;
+
+ entry->limit_low = limit & 0xFFFF;
+ entry->granularity = (limit >> 16 & 0x0F) | (gran & 0xF0);
+
+ entry->access = access;
+ entry->reserved0 = 0;
+}
+
+void Init()
+{
+
+#if defined(__i386__)
+ const uint8_t gran = GRAN_4KIB_BLOCKS | GRAN_32_BIT_MODE;
+#elif defined(__x86_64__)
+ const uint8_t gran = GRAN_4KIB_BLOCKS | GRAN_64_BIT_MODE;
+#endif
+
+ SetGate(0, 0, 0, 0, 0); // Null segment
+ SetGate(1, 0, 0xFFFFFFFF, 0x9A, gran); // Code segment
+ SetGate(2, 0, 0xFFFFFFFF, 0x92, gran); // Data segment
+ SetGate(3, 0, 0xFFFFFFFF, 0xFA, gran); // User mode code segment
+ SetGate(4, 0, 0xFFFFFFFF, 0xF2, gran); // User mode data segment
+
+ WriteTSS(5, 0x10, 0x0);
+
+ // Reload the Global Descriptor Table.
+ volatile struct gdt_ptr gdt_ptr;
+ gdt_ptr.limit = (sizeof(struct gdt_entry) * GDT_NUM_ENTRIES) - 1;
+ gdt_ptr.base = (uintptr_t) &gdt_entries;
+ asm volatile ("lgdt (%0)" : : "r"(&gdt_ptr));
+
+ // Switch the current data segment.
+ asm volatile ("mov %0, %%ds\n"
+ "mov %0, %%es\n"
+ "mov %0, %%fs\n"
+ "mov %0, %%gs\n"
+ "mov %0, %%ss\n" : :
+ "r"(KDS));
+
+ // Switch the current code segment.
+ #if defined(__i386__)
+ asm volatile ("push %0\n"
+ "push $1f\n"
+ "retf\n"
+ "1:\n" : :
+ "r"(KCS));
+ #elif defined(__x86_64__)
+ asm volatile ("push %0\n"
+ "push $1f\n"
+ "retfq\n"
+ "1:\n" : :
+ "r"(KCS));
+ #endif
+
+ // Load the task state register - The index is 0x28, as it is the 5th
+ // selector and each is 8 bytes long, but we set the bottom two bits (making
+ // 0x2B) so that it has an RPL of 3, not zero.
+ asm volatile ("ltr %%ax" : : "a"(0x2B));
+}
+
+// Initialise our task state segment structure.
+void WriteTSS(int32_t num, uint16_t ss0, uintptr_t stack0)
+{
+ // First, let's compute the base and limit of our entry in the GDT.
+ uintptr_t base = (uintptr_t) &tss_entry;
+ uint32_t limit = base + sizeof(tss_entry);
+
+ // Now, add our TSS descriptor's address to the GDT.
+#if defined(__i386__)
+ SetGate(num, base, limit, 0xE9, 0x00);
+#elif defined(__x86_64__)
+ SetGate64(num, base, limit, 0xE9, 0x00);
+#endif
+
+ // Ensure the descriptor is initially zero.
+ memset(&tss_entry, 0, sizeof(tss_entry));
+
+#if defined(__i386__)
+ tss_entry.ss0 = ss0; // Set the kernel stack segment.
+ tss_entry.esp0 = stack0; // Set the kernel stack pointer.
+
+ // Here we set the cs, ss, ds, es, fs and gs entries in the TSS.
+ // These specify what segments should be loaded when the processor
+ // switches to kernel mode. Therefore they are just our normal
+ // kernel code/data segments - 0x08 and 0x10 respectively, but with
+ // the last two bits set, making 0x0b and 0x13. The setting of these
+ // bits sets the RPL (requested privilege level) to 3, meaning that
+ // this TSS can be used to switch to kernel mode from ring 3.
+ tss_entry.cs = KCS | 0x3;
+ tss_entry.ss = tss_entry.ds = tss_entry.es = tss_entry.fs = tss_entry.gs = KDS | 0x3;
+#elif defined(__x86_64__)
+ (void) ss0;
+ tss_entry.stack0 = stack0;
+#endif
+}
+
+void SetKernelStack(uintptr_t stacklower, size_t stacksize, uintptr_t stackhigher)
+{
+#if defined(__i386__)
+ (void) stacklower;
+ (void) stacksize;
+ tss_entry.esp0 = (uint32_t) stackhigher;
+#elif defined(__x86_64__)
+ (void) stacklower;
+ (void) stacksize;
+ tss_entry.stack0 = (uint64_t) stackhigher;
+#endif
+}
+
+} // namespace GDT
+} // namespace Sortix
diff --git a/sortix/x86-family/gdt.h b/sortix/x86-family/gdt.h
index 634b1614..48a84cd7 100644
--- a/sortix/x86-family/gdt.h
+++ b/sortix/x86-family/gdt.h
@@ -1,6 +1,6 @@
/*******************************************************************************
- Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
+ Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
This file is part of Sortix.
@@ -25,103 +25,14 @@
#ifndef SORTIX_X86_FAMILY_GDT_H
#define SORTIX_X86_FAMILY_GDT_H
-namespace Sortix
-{
- namespace GDT
- {
- // This structure contains the value of one GDT entry.
- // We use the attribute 'packed' to tell GCC not to change
- // any of the alignment in the structure.
- struct gdt_entry_struct
- {
- uint16_t limit_low; // The lower 16 bits of the limit.
- uint16_t base_low; // The lower 16 bits of the base.
- uint8_t base_middle; // The next 8 bits of the base.
- uint8_t access; // Access flags, determine what ring this segment can be used in.
- uint8_t granularity;
- uint8_t base_high; // The last 8 bits of the base.
- } __attribute__((packed));
+namespace Sortix {
+namespace GDT {
- struct gdt_entry64_struct
- {
- uint16_t limit_low;
- uint16_t base_low;
- uint8_t base_middle;
- uint8_t access;
- uint8_t granularity;
- uint8_t base_high;
- uint32_t base_highest;
- uint32_t zero1;
- } __attribute__((packed));
+void Init();
+void WriteTSS(int32_t num, uint16_t ss0, uintptr_t stack0);
+void SetKernelStack(uintptr_t stacklower, size_t stacksize, uintptr_t stackhigher);
- typedef struct gdt_entry_struct gdt_entry_t;
- typedef struct gdt_entry64_struct gdt_entry64_t;
-
- // This struct describes a GDT pointer. It points to the start of
- // our array of GDT entries, and is in the format required by the
- // lgdt instruction.
- struct gdt_ptr_struct
- {
- uint16_t limit; // The upper 16 bits of all selector limits.
- addr_t base; // The address of the first gdt_entry_t struct.
- } __attribute__((packed));
-
- typedef struct gdt_ptr_struct gdt_ptr_t;
-
- // A struct describing a Task State Segment.
-#ifdef PLATFORM_X86
- struct tss_entry_struct
- {
- uint32_t prev_tss; // The previous TSS - if we used hardware task switching this would form a linked list.
- uint32_t esp0; // The stack pointer to load when we change to kernel mode.
- uint32_t ss0; // The stack segment to load when we change to kernel mode.
- uint32_t esp1; // Unused...
- uint32_t ss1;
- uint32_t esp2;
- 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; // The value to load into ES when we change to kernel mode.
- uint32_t cs; // The value to load into CS when we change to kernel mode.
- uint32_t ss; // The value to load into SS when we change to kernel mode.
- uint32_t ds; // The value to load into DS when we change to kernel mode.
- uint32_t fs; // The value to load into FS when we change to kernel mode.
- uint32_t gs; // The value to load into GS when we change to kernel mode.
- uint32_t ldt; // Unused...
- uint16_t trap;
- uint16_t iomap_base;
- } __attribute__((packed));
-#else
- struct tss_entry_struct
- {
- uint32_t reserved1;
- uint64_t stack0;
- uint64_t stack1;
- uint64_t stack2;
- uint64_t reserved2;
- uint64_t ist[7];
- uint64_t reserved3;
- uint16_t reserved4;
- uint16_t iomap_base;
- } __attribute__((packed));
-#endif
-
- typedef struct tss_entry_struct tss_entry_t;
-
- void Init();
- void SetGate(int32_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran);
- void WriteTSS(int32_t num, uint16_t ss0, addr_t stack0);
- void SetKernelStack(addr_t stacklower, size_t stacksize, addr_t stackhigher);
- }
-}
+} // namespace GDT
+} // namespace Sortix
#endif
diff --git a/sortix/x86/gdt.s b/sortix/x86/gdt.s
deleted file mode 100644
index e5fd4f81..00000000
--- a/sortix/x86/gdt.s
+++ /dev/null
@@ -1,65 +0,0 @@
-/*******************************************************************************
-
- Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
-
- This file is part of Sortix.
-
- Sortix is free software: you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation, either version 3 of the License, or (at your option) any later
- version.
-
- Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- Sortix. If not, see .
-
- x86/gdt.s
- Handles initialization of the 32-bit global descriptor table.
-
-*******************************************************************************/
-
-.section .text
-
-.global gdt_flush
-.type gdt_flush, @function
-gdt_flush:
- # Load the new GDT pointer
- mov 4(%esp), %eax
- lgdtl (%eax)
-
- # 0x10 is the offset in the GDT to our data segment
- mov $0x10, %ax
- mov %ax, %ds
- mov %ax, %es
- mov %ax, %fs
- mov %ax, %gs
- mov %ax, %ss
-
- # Far jump to our new code segment!
- movl $GDT_FLUSH_POSTJMP, %eax
- ljmp *(%eax)
-gdt_flush_postjmp:
- ret
-.size gdt_flush, . - gdt_flush
-
-.global tss_flush
-.type tss_flush, @function
-tss_flush:
- # Load the index of our TSS structure - The index is 0x28, as it is the 5th
- # selector and each is 8 bytes long, but we set the bottom two bits (making
- # 0x2B) so that it has an RPL of 3, not zero.
- mov $0x2B, %ax
-
- # Load the task state register.
- ltr %ax
- ret
-.size tss_flush, . - tss_flush
-
-.section .data
-GDT_FLUSH_POSTJMP:
- .long gdt_flush_postjmp
- .word 0x08 # 0x08 is the offset to our code segment