diff --git a/kernel/Makefile b/kernel/Makefile
index e44adbf7..dce5c0e2 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -31,14 +31,14 @@ BOOTOBJS:=
ifeq ($(CPU),x86)
X86FAMILY:=1
CPUDIR:=$(CPU)
- CPUOBJS:=$(CPUDIR)/boot.o $(CPUDIR)/base.o
+ CPUOBJS:=$(CPUDIR)/boot.o
endif
ifeq ($(CPU),x64)
X86FAMILY:=1
CPUDIR:=$(CPU)
CXXFLAGS:=$(CXXFLAGS) -mno-red-zone -mno-mmx -mno-sse -mno-sse2
- CPUOBJS:=$(CPUDIR)/boot.o $(CPUDIR)/base.o
+ CPUOBJS:=$(CPUDIR)/boot.o
endif
ifndef CPUDIR
diff --git a/kernel/include/sortix/kernel/panic.h b/kernel/include/sortix/kernel/panic.h
index 4fd77663..1e4b5db3 100644
--- a/kernel/include/sortix/kernel/panic.h
+++ b/kernel/include/sortix/kernel/panic.h
@@ -1,6 +1,6 @@
/*******************************************************************************
- Copyright(C) Jonas 'Sortie' Termansen 2011, 2013, 2014.
+ Copyright(C) Jonas 'Sortie' Termansen 2011, 2013, 2014, 2015.
This file is part of Sortix.
@@ -30,7 +30,6 @@ namespace Sortix {
extern "C" __attribute__((noreturn)) void HaltKernel();
extern "C" __attribute__((noreturn)) void Panic(const char* error);
extern "C" __attribute__((noreturn, format(printf, 1, 2))) void PanicF(const char* format, ...);
-extern "C" void WaitForInterrupt();
} // namespace Sortix
diff --git a/kernel/include/sortix/kernel/registers.h b/kernel/include/sortix/kernel/registers.h
index 83d3d200..2d4fb1cf 100644
--- a/kernel/include/sortix/kernel/registers.h
+++ b/kernel/include/sortix/kernel/registers.h
@@ -63,6 +63,8 @@ const uint32_t UCS = 0x18;
const uint32_t UDS = 0x20;
const uint32_t URPL = 0x3;
const uint32_t RPLMASK = 0x3;
+#define GDT_FS_ENTRY 6
+#define GDT_GS_ENTRY 7
struct interrupt_context
{
diff --git a/kernel/kernel.cpp b/kernel/kernel.cpp
index b6aba4ff..0f89ff9b 100644
--- a/kernel/kernel.cpp
+++ b/kernel/kernel.cpp
@@ -93,7 +93,7 @@
#include "x86-family/gdt.h"
#endif
-// Keep the stack size aligned with $CPU/base.s
+// Keep the stack size aligned with $CPU/boot.s
const size_t STACK_SIZE = 64*1024;
extern "C" { __attribute__((aligned(16))) size_t stack[STACK_SIZE / sizeof(size_t)]; }
@@ -276,10 +276,6 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
// Initialize paging and virtual memory.
Memory::Init(bootinfo);
- // Initialize the GDT and TSS structures.
- GDT::Init();
- GDT::SetKernelStack((uintptr_t) stack + STACK_SIZE);
-
// Initialize the interrupt handler table and enable interrupts.
Interrupt::Init();
diff --git a/kernel/x64/base.S b/kernel/x64/base.S
deleted file mode 100644
index 0ef50e9d..00000000
--- a/kernel/x64/base.S
+++ /dev/null
@@ -1,67 +0,0 @@
-/*******************************************************************************
-
- Copyright(C) Jonas 'Sortie' Termansen 2011.
-
- 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/base.S
- Bootstraps the kernel and passes over control from the boot-loader to the
- kernel main function.
-
-*******************************************************************************/
-
-.section .text
-
-.global beginkernel
-.type beginkernel, @function
-beginkernel:
- movw $0x736, 0xB83E8
- movw $0x734, 0xB83EA
- movw $0x753, 0xB83EE
- movw $0x74F, 0xB83F0
- movw $0x752, 0xB83F2
- movw $0x754, 0xB83F4
- movw $0x749, 0xB83F6
- movw $0x758, 0xB83F8
-
- # Initialize the stack pointer.
- movq $stack, %rsp
- addq $65536, %rsp # 64 KiB, see kernel.cpp
-
- # Reset EFLAGS.
- # pushl $0
- # popf
-
- # Push the pointer to the Multiboot information structure.
- mov %rbx, %rsi
- # Push the magic value.
- mov %rax, %rdi
-
- call KernelInit
-.size beginkernel, . - beginkernel
-
-.global HaltKernel
-HaltKernel:
- cli
- hlt
- jmp HaltKernel
-.size HaltKernel, . - HaltKernel
-
-.global WaitForInterrupt
-.type WaitForInterrupt, @function # void WaitForInterrupt();
-WaitForInterrupt:
- hlt
- ret
diff --git a/kernel/x64/boot.S b/kernel/x64/boot.S
index 373f1d3b..ff95ee25 100644
--- a/kernel/x64/boot.S
+++ b/kernel/x64/boot.S
@@ -1,6 +1,6 @@
/*******************************************************************************
- Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
+ Copyright(C) Jonas 'Sortie' Termansen 2011, 2014, 2015.
This file is part of Sortix.
@@ -26,6 +26,12 @@
.section .text
.text 0x100000
+ # Multiboot header.
+ .align 4
+ .long 0x1BADB002 # Magic.
+ .long 0x00000003 # Flags.
+ .long -(0x1BADB002 + 0x00000003) # Checksum
+
.global _start
.global __start
.type _start, @function
@@ -33,34 +39,31 @@
.code32
_start:
__start:
- jmp prepare_kernel_execution
+ # Initialize the stack pointer. The magic value is from kernel.cpp.
+ movl $(stack + 65536), %esp # 64 KiB, see kernel.cpp (See below also)
- # Align 32 bits boundary.
- .align 4
+ # Finish installing the kernel stack into the Task Switch Segment.
+ movl %esp, tss + 4
+ movl $0, tss + 8
- # Multiboot header.
-multiboot_header:
- # Magic.
- .long 0x1BADB002
- # Flags.
- .long 0x00000003
- # Checksum.
- .long -(0x1BADB002 + 0x00000003)
+ # Finish installing the Task Switch Segment into the Global Descriptor Table.
+ movl $tss, %ecx
+ movw %cx, gdt + 0x28 + 2
+ shrl $16, %ecx
+ movb %cl, gdt + 0x28 + 4
+ shrl $8, %ecx
+ movb %cl, gdt + 0x28 + 7
+ movl $0, gdt + 0x28 + 8
-prepare_kernel_execution:
- # We got our multiboot information in various registers. But we are going
- # to need these registers. But where can we store them then? Oh hey, let's
- # store then in the code already run!
-
- # Store the pointer to the Multiboot information structure.
- mov %ebx, 0x100000
-
- # Store the magic value.
- mov %eax, 0x100004
+ # We got our multiboot information in various registers.
+ pushl $0
+ pushl %eax # Multiboot magic value.
+ pushl $0
+ pushl %ebx # Multiboot information structure pointer.
# Clear the first $0xE000 bytes following 0x21000.
movl $0x21000, %edi
- mov %edi, %cr3
+ movl %edi, %cr3
xorl %eax, %eax
movl $0xE000, %ecx
rep stosl
@@ -88,45 +91,56 @@ prepare_kernel_execution:
movl $0x3, %ebx
movl $1024, %ecx
-SetEntry:
- mov %ebx, (%edi)
- add $0x1000, %ebx
- add $8, %edi
- loop SetEntry
+1:
+ movl %ebx, (%edi)
+ addl $0x1000, %ebx
+ addl $8, %edi
+ loop 1b
# Enable PAE.
- mov %cr4, %eax
+ movl %cr4, %eax
orl $0x20, %eax
- mov %eax, %cr4
+ movl %eax, %cr4
# Enable long mode.
- mov $0xC0000080, %ecx
+ movl $0xC0000080, %ecx
rdmsr
orl $0x100, %eax
wrmsr
# Enable paging and enter long mode (still 32-bit)
- mov %cr0, %eax
+ movl %cr0, %eax
orl $0x80000000, %eax
- mov %eax, %cr0
+ movl %eax, %cr0
- # Load the long mode GDT.
- mov GDTPointer, %eax
- lgdtl GDTPointer
+ # Load the Global Descriptor Table pointer register.
+ subl $6, %esp
+ movw gdt_size_minus_one, %cx
+ movw %cx, 0(%esp)
+ movl $gdt, %ecx
+ movl %ecx, 2(%esp)
+ lgdt 0(%esp)
+ addl $6, %esp
# Now use the 64-bit code segment, and we are in full 64-bit mode.
- ljmp $0x10, $Realm64
+ ljmp $0x08, $2f
.code64
-Realm64:
+2:
+ # Switch ds, es, fs, gs, ss to the kernel data segment (0x10).
+ movw $0x10, %cx
+ movw %cx, %ds
+ movw %cx, %es
+ movw %cx, %ss
- # Now, set up the other segment registers.
- cli
- mov $0x18, %ax
- mov %ax, %ds
- mov %ax, %es
- mov %ax, %fs
- mov %ax, %gs
+ # Switch the task switch segment register to the task switch segment (0x28).
+ movw $(0x28 /* TSS */ | 0x3 /* RPL */), %cx
+ ltr %cx
+
+ # Switch to the thread local fs and gs segments.
+ movw $(0x20 /* DS */ | 0x3 /* RPL */), %cx
+ movw %cx, %fs
+ movw %cx, %gs
# Enable the floating point unit.
mov %cr0, %rax
@@ -147,58 +161,18 @@ Realm64:
# Store a copy of the initialial floating point registers.
fxsave fpu_initialized_regs
- # Alright, that was the bootstrap code. Now begin preparing to run the
- # actual 64-bit kernel.
- jmp Main
+ # Enter the high-level kernel proper.
+ pop %rsi # Multiboot information structure pointer.
+ pop %rdi # Multiboot magic value.
+ call KernelInit
+
+ jmp HaltKernel
.size _start, . - _start
.size __start, . - __start
-
-.section .data
-GDT64: # Global Descriptor Table (64-bit).
- GDTNull: # The null descriptor.
- .word 0 # Limit (low).
- .word 0 # Base (low).
- .byte 0 # Base (middle)
- .byte 0 # Access.
- .byte 0 # Granularity.
- .byte 0 # Base (high).
- GDTUnused: # The null descriptor.
- .word 0 # Limit (low).
- .word 0 # Base (low).
- .byte 0 # Base (middle)
- .byte 0 # Access.
- .byte 0 # Granularity.
- .byte 0 # Base (high).
- GDTCode: # The code descriptor.
- .word 0xFFFF # Limit (low).
- .word 0 # Base (low).
- .byte 0 # Base (middle)
- .byte 0x9A # Access.
- .byte 0xAF # Granularity.
- .byte 0 # Base (high).
- GDTData: # The data descriptor.
- .word 0xFFFF # Limit (low).
- .word 0 # Base (low).
- .byte 0 # Base (middle)
- .byte 0x92 # Access.
- .byte 0x8F # Granularity.
- .byte 0 # Base (high).
- GDTPointer: # The GDT-pointer.
- .word GDTPointer - GDT64 - 1 # Limit.
- .long GDT64 # Base.
- .long 0
-
-Main:
- # Copy the character B onto the screen so we know it works.
- movq $0x242, %r15
- movq %r15, %rax
- movw %ax, 0xB8000
-
- # Load the pointer to the Multiboot information structure.
- mov 0x100000, %ebx
-
- # Load the magic value.
- mov 0x100004, %eax
-
- jmp beginkernel
-.size Main, . - Main
+.global HaltKernel
+.type HaltKernel, @function
+HaltKernel:
+ cli
+ hlt
+ jmp HaltKernel
+.size HaltKernel, . - HaltKernel
diff --git a/kernel/x86-family/gdt.cpp b/kernel/x86-family/gdt.cpp
index 71aad78d..478e90f3 100644
--- a/kernel/x86-family/gdt.cpp
+++ b/kernel/x86-family/gdt.cpp
@@ -1,6 +1,6 @@
/*******************************************************************************
- Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
+ Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014, 2015.
This file is part of Sortix.
@@ -18,7 +18,7 @@
Sortix. If not, see .
x86-family/gdt.cpp
- Initializes and handles the GDT and TSS.
+ GDT and TSS.
*******************************************************************************/
@@ -44,6 +44,7 @@ struct gdt_entry
uint8_t base_high;
};
+#if defined(__x86_64__)
struct gdt_entry64
{
uint16_t limit_low;
@@ -55,25 +56,15 @@ struct gdt_entry64
uint32_t base_highest;
uint32_t reserved0;
};
-
-// TODO: Do this in another way that doesn't require a silly structure .
-struct gdt_ptr
-{
- uint16_t limit;
-#if defined(__i386__)
- uint32_t base;
-#else
- 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 prev_tss;
+ uint32_t esp0;
+ uint32_t ss0;
+ uint32_t esp1;
uint32_t ss1;
uint32_t esp2;
uint32_t ss2;
@@ -88,13 +79,13 @@ struct tss_entry
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...
+ uint32_t es;
+ uint32_t cs;
+ uint32_t ss;
+ uint32_t ds;
+ uint32_t fs;
+ uint32_t gs;
+ uint32_t ldt;
uint16_t trap;
uint16_t iomap_base;
};
@@ -105,164 +96,148 @@ struct tss_entry
uint64_t stack0; /* This is not naturally aligned, so packed is needed. */
uint64_t stack1;
uint64_t stack2;
- uint64_t reserved2;
+ uint64_t reserved1;
uint64_t ist[7];
- uint64_t reserved3;
- uint16_t reserved4;
+ uint64_t reserved2;
+ uint16_t reserved3;
uint16_t iomap_base;
} __attribute__((packed));
#endif
-#if defined(__i386__)
-const size_t GDT_NUM_ENTRIES = 9;
-const size_t GDT_FS_ENTRY = 7;
-const size_t GDT_GS_ENTRY = 8;
-#else
-const size_t GDT_NUM_ENTRIES = 7;
-#endif
-static struct gdt_entry gdt_entries[GDT_NUM_ENTRIES];
+extern "C" {
-static struct tss_entry tss_entry;
+const size_t STACK_SIZE = 64*1024;
+extern size_t stack[STACK_SIZE / sizeof(size_t)];
-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 tss_entry tss =
{
- struct gdt_entry* entry = (struct gdt_entry*) &gdt_entries[num];
+#if defined(__i386__)
+ .prev_tss = 0, /* c++ */
+ .esp0 = 0 /*(uintptr_t) stack + sizeof(stack)*/,
+ .ss0 = 0x10 /* Kernel Data Segment */,
+ .esp1 = 0, /* c++ */
+ .ss1 = 0, /* c++ */
+ .esp2 = 0, /* c++ */
+ .ss2 = 0, /* c++ */
+ .cr3 = 0, /* c++ */
+ .eip = 0, /* c++ */
+ .eflags = 0, /* c++ */
+ .eax = 0, /* c++ */
+ .ecx = 0, /* c++ */
+ .edx = 0, /* c++ */
+ .ebx = 0, /* c++ */
+ .esp = 0, /* c++ */
+ .ebp = 0, /* c++ */
+ .esi = 0, /* c++ */
+ .edi = 0, /* c++ */
+ .es = 0x13 /* Kernel Data Segment */,
+ .cs = 0x0B /* Kernel Code Segment */,
+ .ss = 0, /* c++ */
+ .ds = 0x13 /* Kernel Data Segment */,
+ .fs = 0x13 /* Kernel Data Segment */,
+ .gs = 0x13 /* Kernel Data Segment */,
+ .ldt = 0, /* c++ */
+ .trap = 0, /* c++ */
+ .iomap_base = 0, /* c++ */
+#elif defined(__x86_64__)
+ .reserved0 = 0, /* c++ */
+ .stack0 = 0 /*(uintptr_t) stack + sizeof(stack)*/,
+ .stack1 = 0, /* c++ */
+ .stack2 = 0, /* c++ */
+ .reserved1 = 0, /* c++ */
+ .ist = { 0, 0, 0, 0, 0, 0, 0},
+ .reserved2 = 0,
+ .reserved3 = 0,
+ .iomap_base = 0,
+#endif
+};
- entry->base_low = base >> 0 & 0xFFFF;
- entry->base_middle = base >> 16 & 0xFF;
- entry->base_high = base >> 24 & 0xFF;
+} // extern "C"
- entry->limit_low = limit & 0xFFFF;
- entry->granularity = (limit >> 16 & 0x0F) | (gran & 0xF0);
+#define GRAN_64_BIT_MODE (1 << 5)
+#define GRAN_32_BIT_MODE (1 << 6)
+#define GRAN_4KIB_BLOCKS (1 << 7)
- entry->access = access;
-}
+#define GDT_ENTRY(base, limit, access, granularity) \
+ { (limit) & 0xFFFF, /* limit_low */ \
+ (uint16_t) ((base) >> 0 & 0xFFFF), /* base_low */ \
+ (uint8_t) ((base) >> 16 & 0xFF), /* base_middle */ \
+ (access) & 0xFF, /* access */ \
+ ((limit) >> 16 & 0x0F) | ((granularity) & 0xF0), /* granularity */ \
+ (uint8_t) ((base) >> 24 & 0xFF), /* base_high */ }
-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(__x86_64__)
+#define GDT_ENTRY64(base, limit, access, granularity) \
+ { (limit) & 0xFFFF, /* limit_low */ \
+ (uint16_t) ((base) >> 0 & 0xFFFF), /* base_low */ \
+ (uint8_t) ((base) >> 16 & 0xFF), /* base_middle */ \
+ (access) & 0xFF, /* access */ \
+ ((limit) >> 16 & 0x0F) | ((granularity) & 0xF0), /* granularity */ \
+ (uint8_t) ((base) >> 24 & 0xFF), /* base_high */ }, \
+ { (uint16_t) ((base) >> 32 & 0xFFFF), /* base_highest */ \
+ (uint16_t) ((base) >> 48 & 0xFFFF), /* base_highest */ \
+ 0, /* reserved0 */ \
+ 0, /* reserved0 */ \
+ 0, /* reserved0 */ \
+ 0, /* reserved0 */ }
+#endif
+
+extern "C" {
+
+struct gdt_entry gdt[] =
{
+ /* 0x00: Null segment */
+ GDT_ENTRY(0, 0, 0, 0),
#if defined(__i386__)
- const uint8_t gran = GRAN_4KIB_BLOCKS | GRAN_32_BIT_MODE;
+ /* 0x08: Kernel Code Segment. */
+ GDT_ENTRY(0, 0xFFFFFFFF, 0x9A, GRAN_32_BIT_MODE | GRAN_4KIB_BLOCKS),
+
+ /* 0x10: Kernel Data Segment. */
+ GDT_ENTRY(0, 0xFFFFFFFF, 0x92, GRAN_32_BIT_MODE | GRAN_4KIB_BLOCKS),
+
+ /* 0x18: User Code Segment. */
+ GDT_ENTRY(0, 0xFFFFFFFF, 0xFA, GRAN_32_BIT_MODE | GRAN_4KIB_BLOCKS),
+
+ /* 0x20: User Data Segment. */
+ GDT_ENTRY(0, 0xFFFFFFFF, 0xF2, GRAN_32_BIT_MODE | GRAN_4KIB_BLOCKS),
+
+ /* 0x28: Task Switch Segment. */
+ GDT_ENTRY(0 /*((uintptr_t) &tss)*/, sizeof(tss) - 1, 0xE9, 0x00),
+
+ /* 0x30: F Segment. */
+ GDT_ENTRY(0, 0xFFFFFFFF, 0xF2, GRAN_32_BIT_MODE | GRAN_4KIB_BLOCKS),
+
+ /* 0x38: G Segment. */
+ GDT_ENTRY(0, 0xFFFFFFFF, 0xF2, GRAN_32_BIT_MODE | GRAN_4KIB_BLOCKS),
#elif defined(__x86_64__)
- const uint8_t gran = GRAN_4KIB_BLOCKS | GRAN_64_BIT_MODE;
+ /* 0x08: Kernel Code Segment. */
+ GDT_ENTRY(0, 0xFFFFFFFF, 0x9A, GRAN_64_BIT_MODE | GRAN_4KIB_BLOCKS),
+
+ /* 0x10: Kernel Data Segment. */
+ GDT_ENTRY(0, 0xFFFFFFFF, 0x92, GRAN_64_BIT_MODE | GRAN_4KIB_BLOCKS),
+
+ /* 0x18: User Code Segment. */
+ GDT_ENTRY(0, 0xFFFFFFFF, 0xFA, GRAN_64_BIT_MODE | GRAN_4KIB_BLOCKS),
+
+ /* 0x20: User Data Segment. */
+ GDT_ENTRY(0, 0xFFFFFFFF, 0xF2, GRAN_64_BIT_MODE | GRAN_4KIB_BLOCKS),
+
+ /* 0x28: Task Switch Segment. */
+ GDT_ENTRY64((uint64_t) 0 /*((uintptr_t) &tss)*/, sizeof(tss) - 1, 0xE9, 0x00),
#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
+uint16_t gdt_size_minus_one = sizeof(gdt) - 1;
- WriteTSS(5, 0x10, 0x0);
-
-#if defined(__i386__)
- SetGate(GDT_FS_ENTRY, 0, 0xFFFFFFFF, 0xF2, gran);
- SetGate(GDT_GS_ENTRY, 0, 0xFFFFFFFF, 0xF2, gran);
-#endif
-
- // 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, %%ss\n" : :
- "r"(KDS));
-
-#if defined(__i386__)
- asm volatile ("mov %0, %%fs" : : "r"(GDT_FS_ENTRY << 3 | URPL));
- asm volatile ("mov %0, %%gs" : : "r"(GDT_GS_ENTRY << 3 | URPL));
-#elif defined(__x86_64__)
- asm volatile ("mov %0, %%fs" : : "r"(UDS | URPL));
- asm volatile ("mov %0, %%gs" : : "r"(UDS | URPL));
-#endif
-
- // 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 = sizeof(tss_entry) - 1;
-
- // 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
-}
+} // extern "C"
uintptr_t GetKernelStack()
{
#if defined(__i386__)
- return tss_entry.esp0;
+ return tss.esp0;
#elif defined(__x86_64__)
- return tss_entry.stack0;
+ return tss.stack0;
#endif
}
@@ -270,16 +245,16 @@ void SetKernelStack(uintptr_t stack_pointer)
{
assert((stack_pointer & 0xF) == 0);
#if defined(__i386__)
- tss_entry.esp0 = (uint32_t) stack_pointer;
+ tss.esp0 = (uint32_t) stack_pointer;
#elif defined(__x86_64__)
- tss_entry.stack0 = (uint64_t) stack_pointer;
+ tss.stack0 = (uint64_t) stack_pointer;
#endif
}
#if defined(__i386__)
uint32_t GetFSBase()
{
- struct gdt_entry* entry = gdt_entries + GDT_FS_ENTRY;
+ struct gdt_entry* entry = gdt + GDT_FS_ENTRY;
return (uint32_t) entry->base_low << 0 |
(uint32_t) entry->base_middle << 16 |
(uint32_t) entry->base_high << 24;
@@ -287,7 +262,7 @@ uint32_t GetFSBase()
uint32_t GetGSBase()
{
- struct gdt_entry* entry = gdt_entries + GDT_GS_ENTRY;
+ struct gdt_entry* entry = gdt + GDT_GS_ENTRY;
return (uint32_t) entry->base_low << 0 |
(uint32_t) entry->base_middle << 16 |
(uint32_t) entry->base_high << 24;
@@ -295,7 +270,7 @@ uint32_t GetGSBase()
void SetFSBase(uint32_t fsbase)
{
- struct gdt_entry* entry = gdt_entries + GDT_FS_ENTRY;
+ struct gdt_entry* entry = gdt + GDT_FS_ENTRY;
entry->base_low = fsbase >> 0 & 0xFFFF;
entry->base_middle = fsbase >> 16 & 0xFF;
entry->base_high = fsbase >> 24 & 0xFF;
@@ -304,7 +279,7 @@ void SetFSBase(uint32_t fsbase)
void SetGSBase(uint32_t gsbase)
{
- struct gdt_entry* entry = gdt_entries + GDT_GS_ENTRY;
+ struct gdt_entry* entry = gdt + GDT_GS_ENTRY;
entry->base_low = gsbase >> 0 & 0xFFFF;
entry->base_middle = gsbase >> 16 & 0xFF;
entry->base_high = gsbase >> 24 & 0xFF;
diff --git a/kernel/x86-family/gdt.h b/kernel/x86-family/gdt.h
index 1fbd5789..df503f12 100644
--- a/kernel/x86-family/gdt.h
+++ b/kernel/x86-family/gdt.h
@@ -1,6 +1,6 @@
/*******************************************************************************
- Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
+ Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014, 2015.
This file is part of Sortix.
@@ -18,7 +18,7 @@
Sortix. If not, see .
x86-family/gdt.h
- Initializes and handles the GDT and TSS.
+ GDT and TSS.
*******************************************************************************/
@@ -31,7 +31,6 @@ namespace Sortix {
namespace GDT {
void Init();
-void WriteTSS(int32_t num, uint16_t ss0, uintptr_t stack0);
uintptr_t GetKernelStack();
void SetKernelStack(uintptr_t stack_pointer);
#if defined(__i386__)
diff --git a/kernel/x86/base.S b/kernel/x86/base.S
deleted file mode 100644
index e6b533fb..00000000
--- a/kernel/x86/base.S
+++ /dev/null
@@ -1,62 +0,0 @@
-/*******************************************************************************
-
- Copyright(C) Jonas 'Sortie' Termansen 2011.
-
- 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/base.S
- Bootstraps the kernel and passes over control from the boot-loader to the
- kernel main function.
-
-*******************************************************************************/
-
-.section .text
-
-.global beginkernel
-.type beginkernel, @function
-beginkernel:
- # Initialize the stack pointer. The magic value is from kernel.cpp.
- movl $stack, %esp
- addl $65536, %esp # 64 KiB, see kernel.cpp
-
- # Reset EFLAGS.
- # pushl $0
- # popf
-
- # Push the pointer to the Multiboot information structure.
- push %ebx
- # Push the magic value.
- push %eax
-
- ## Disable interrupts.
- cli
-
- call KernelInit
-.size beginkernel, . - beginkernel
-
-.global HaltKernel
-HaltKernel:
- cli
- hlt
- jmp HaltKernel
-.size HaltKernel, . - HaltKernel
-
-.global WaitForInterrupt
-.type WaitForInterrupt, @function # void WaitForInterrupt();
-WaitForInterrupt:
- hlt
- ret
-.size WaitForInterrupt, . - WaitForInterrupt
diff --git a/kernel/x86/boot.S b/kernel/x86/boot.S
index e98633f0..3ed45951 100644
--- a/kernel/x86/boot.S
+++ b/kernel/x86/boot.S
@@ -1,6 +1,6 @@
/*******************************************************************************
- Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
+ Copyright(C) Jonas 'Sortie' Termansen 2011, 2014, 2015.
This file is part of Sortix.
@@ -26,48 +26,96 @@
.section .text
.text 0x100000
+ # Multiboot header.
+ .align 4
+ .long 0x1BADB002 # Magic.
+ .long 0x00000003 # Flags.
+ .long -(0x1BADB002 + 0x00000003) # Checksum.
+
.global _start
.global __start
.type _start, @function
.type __start, @function
_start:
__start:
- jmp prepare_kernel_execution
+ # Initialize the stack pointer. The magic value is from kernel.cpp.
+ movl $(stack + 65536), %esp # 64 KiB, see kernel.cpp
- # Align 32 bits boundary.
- .align 4
+ # Finish installing the kernel stack into the Task Switch Segment.
+ movl %esp, tss + 4
- # Multiboot header.
-multiboot_header:
- # Magic.
- .long 0x1BADB002
- # Flags.
- .long 0x00000003
- # Checksum.
- .long -(0x1BADB002 + 0x00000003)
+ # Finish installing the Task Switch Segment into the Global Descriptor Table.
+ movl $tss, %ecx
+ movw %cx, gdt + 0x28 + 2
+ shrl $16, %ecx
+ movb %cl, gdt + 0x28 + 4
+ shrl $8, %ecx
+ movb %cl, gdt + 0x28 + 7
+
+ # Load the Global Descriptor Table pointer register.
+ subl $6, %esp
+ movw gdt_size_minus_one, %cx
+ movw %cx, 0(%esp)
+ movl $gdt, %ecx
+ movl %ecx, 2(%esp)
+ lgdt 0(%esp)
+ addl $6, %esp
+
+ # Switch cs to the kernel code segment (0x08).
+ push $0x08
+ push $2f
+ retf
+
+2:
+ # Switch ds, es, fs, gs, ss to the kernel data segment (0x10).
+ movw $0x10, %cx
+ movw %cx, %ds
+ movw %cx, %es
+ movw %cx, %ss
+
+ # Switch the task switch segment register to the task switch segment (0x28).
+ movw $(0x28 /* TSS */ | 0x3 /* RPL */), %cx
+ ltr %cx
+
+ # Switch to the thread local fs and gs segments.
+ movw $(0x30 /* FS */ | 0x3 /* RPL */), %cx
+ movw %cx, %fs
+ movw $(0x38 /* GS */ | 0x3 /* RPL */), %cx
+ movw %cx, %gs
-prepare_kernel_execution:
# Enable the floating point unit.
- mov %eax, 0x100000
- mov %cr0, %eax
- and $0xFFFD, %ax
- or $0x10, %ax
- mov %eax, %cr0
+ mov %cr0, %ecx
+ and $0xFFFD, %cx
+ or $0x10, %cx
+ mov %ecx, %cr0
fninit
# Enable Streaming SIMD Extensions.
- mov %cr0, %eax
- and $0xFFFB, %ax
- or $0x2, %ax
- mov %eax, %cr0
- mov %cr4, %eax
- or $0x600, %eax
- mov %eax, %cr4
- mov 0x100000, %eax
+ mov %cr0, %ecx
+ and $0xFFFB, %cx
+ or $0x2, %cx
+ mov %ecx, %cr0
+ mov %cr4, %ecx
+ or $0x600, %ecx
+ mov %ecx, %cr4
# Store a copy of the initialial floating point registers.
fxsave fpu_initialized_regs
- jmp beginkernel
+ # Enter the high-level kernel proper.
+ subl $8, %esp # 16-byte align at call time.
+ push %ebx # Multiboot information structure pointer.
+ push %eax # Multiboot magic value.
+ call KernelInit
+
+ jmp HaltKernel
.size _start, . - _start
.size __start, . - __start
+
+.global HaltKernel
+.type HaltKernel, @function
+HaltKernel:
+ cli
+ hlt
+ jmp HaltKernel
+.size HaltKernel, . - HaltKernel