From a422c394b81c4926d1125f2e202d9328f33fe695 Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Mon, 16 Mar 2015 00:14:21 +0100 Subject: [PATCH] Initialize the GDT in the bootstrap assembly. --- kernel/Makefile | 4 +- kernel/include/sortix/kernel/panic.h | 3 +- kernel/include/sortix/kernel/registers.h | 2 + kernel/kernel.cpp | 6 +- kernel/x64/base.S | 67 ----- kernel/x64/boot.S | 170 ++++++------- kernel/x86-family/gdt.cpp | 301 +++++++++++------------ kernel/x86-family/gdt.h | 5 +- kernel/x86/base.S | 62 ----- kernel/x86/boot.S | 102 ++++++-- 10 files changed, 293 insertions(+), 429 deletions(-) delete mode 100644 kernel/x64/base.S delete mode 100644 kernel/x86/base.S 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