mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
291 lines
8.9 KiB
C++
291 lines
8.9 KiB
C++
/*******************************************************************************
|
|
|
|
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014, 2015.
|
|
|
|
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 <http://www.gnu.org/licenses/>.
|
|
|
|
x86-family/gdt.cpp
|
|
GDT and TSS.
|
|
|
|
*******************************************************************************/
|
|
|
|
#include <assert.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#include <sortix/kernel/cpu.h>
|
|
#include <sortix/kernel/registers.h>
|
|
|
|
#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
|