/* * Copyright (c) 2011, 2012, 2013, 2014, 2015 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * x86-family/gdt.cpp * GDT and TSS. */ #include #include #include #include #include #include "gdt.h" namespace Sortix { namespace GDT { struct gdt_entry { uint16_t limit_low; uint16_t base_low; uint8_t base_middle; uint8_t access; uint8_t granularity; uint8_t base_high; }; #if defined(__x86_64__) 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; }; #endif #if defined(__i386__) struct tss_entry { uint32_t prev_tss; uint32_t esp0; uint32_t ss0; uint32_t esp1; 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; 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; }; #elif defined(__x86_64__) struct tss_entry { uint32_t reserved0; uint64_t stack0; /* This is not naturally aligned, so packed is needed. */ uint64_t stack1; uint64_t stack2; uint64_t reserved1; uint64_t ist[7]; uint64_t reserved2; uint16_t reserved3; uint16_t iomap_base; } __attribute__((packed)); #endif extern "C" { const size_t STACK_SIZE = 64*1024; extern size_t stack[STACK_SIZE / sizeof(size_t)]; struct tss_entry tss = { #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 }; } /* extern "C" */ #define GRAN_64_BIT_MODE (1 << 5) #define GRAN_32_BIT_MODE (1 << 6) #define GRAN_4KIB_BLOCKS (1 << 7) #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 */ } #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__) /* 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__) /* 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 }; uint16_t gdt_size_minus_one = sizeof(gdt) - 1; } /* extern "C" */ uintptr_t GetKernelStack() { #if defined(__i386__) return tss.esp0; #elif defined(__x86_64__) return tss.stack0; #endif } void SetKernelStack(uintptr_t stack_pointer) { assert((stack_pointer & 0xF) == 0); #if defined(__i386__) tss.esp0 = (uint32_t) stack_pointer; #elif defined(__x86_64__) tss.stack0 = (uint64_t) stack_pointer; #endif } #if defined(__i386__) uint32_t GetFSBase() { 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; } uint32_t GetGSBase() { 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; } void SetFSBase(uint32_t fsbase) { 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; asm volatile ("mov %0, %%fs" : : "r"(GDT_FS_ENTRY << 3 | URPL)); } void SetGSBase(uint32_t gsbase) { 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; asm volatile ("mov %0, %%gs" : : "r"(GDT_GS_ENTRY << 3 | URPL)); } #endif } // namespace GDT } // namespace Sortix