mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Split descriptor_tables.cpp into a gdt.cpp and idt.cpp.
This was about time, since descriptor_tables was a really bad name!
This commit is contained in:
parent
5162a12d03
commit
b4f47f0f79
14 changed files with 212 additions and 118 deletions
158
sortix/x86-family/gdt.cpp
Normal file
158
sortix/x86-family/gdt.cpp
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
/*******************************************************************************
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
x86-family/gdt.cpp
|
||||
Initializes and handles the GDT and TSS.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include "../platform.h"
|
||||
#include <libmaxsi/memory.h>
|
||||
#include "gdt.h"
|
||||
|
||||
using namespace Maxsi;
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
namespace GDT
|
||||
{
|
||||
extern "C" void gdt_flush(addr_t);
|
||||
extern "C" void tss_flush();
|
||||
|
||||
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;
|
||||
|
||||
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.
|
||||
Memory::Set(&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)
|
||||
tss_entry.stack0 = stack0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SetKernelStack(size_t* stack)
|
||||
{
|
||||
#ifdef PLATFORM_X86
|
||||
tss_entry.esp0 = (uint32_t) stack;
|
||||
#elif defined(PLATFORM_X64)
|
||||
tss_entry.stack0 = (uint64_t) stack;
|
||||
#else
|
||||
#warning "TSS is not yet supported on this arch!"
|
||||
while(true);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
128
sortix/x86-family/gdt.h
Normal file
128
sortix/x86-family/gdt.h
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
/*******************************************************************************
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
x86-family/gdt.h
|
||||
Initializes and handles the GDT and TSS.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#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));
|
||||
|
||||
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));
|
||||
|
||||
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(size_t* stack);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
68
sortix/x86-family/idt.cpp
Normal file
68
sortix/x86-family/idt.cpp
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*******************************************************************************
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
x86-family/idt.cpp
|
||||
Initializes and handles the IDT.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include "../platform.h"
|
||||
#include <libmaxsi/memory.h>
|
||||
#include "idt.h"
|
||||
|
||||
using namespace Maxsi;
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
namespace IDT
|
||||
{
|
||||
extern "C" void idt_flush(addr_t);
|
||||
|
||||
idt_entry_t idt_entries[256];
|
||||
idt_ptr_t idt_ptr;
|
||||
|
||||
void Init()
|
||||
{
|
||||
idt_ptr.limit = sizeof(idt_entry_t) * 256 - 1;
|
||||
idt_ptr.base = (addr_t) &idt_entries;
|
||||
|
||||
Memory::Set(&idt_entries, 0, sizeof(idt_entry_t)*256);
|
||||
}
|
||||
|
||||
void Flush()
|
||||
{
|
||||
idt_flush((addr_t) &idt_ptr);
|
||||
}
|
||||
|
||||
void SetGate(uint8_t num, addr_t base, uint16_t sel, uint8_t flags)
|
||||
{
|
||||
idt_entries[num].base_low = base & 0xFFFF;
|
||||
idt_entries[num].base_high = (base >> 16) & 0xFFFF;
|
||||
#ifdef PLATFORM_X64
|
||||
idt_entries[num].base_highest = (base >> 32 ) & 0xFFFFFFFFU;
|
||||
idt_entries[num].zero1 = 0;
|
||||
#endif
|
||||
|
||||
idt_entries[num].sel = sel;
|
||||
idt_entries[num].always0 = 0;
|
||||
idt_entries[num].flags = flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
78
sortix/x86-family/idt.h
Normal file
78
sortix/x86-family/idt.h
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/*******************************************************************************
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
x86-family/idt.h
|
||||
Initializes and handles the IDT.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_X86_FAMILY_IDT_H
|
||||
#define SORTIX_X86_FAMILY_IDT_H
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
namespace IDT
|
||||
{
|
||||
// A struct describing an interrupt gate.
|
||||
struct idt_entry32_struct
|
||||
{
|
||||
uint16_t base_low; // The lower 16 bits of the address to jump to when this interrupt fires.
|
||||
uint16_t sel; // Kernel segment selector.
|
||||
uint8_t always0; // This must always be zero.
|
||||
uint8_t flags; // More flags. See documentation.
|
||||
uint16_t base_high; // The upper 16 bits of the address to jump to.
|
||||
} __attribute__((packed));
|
||||
|
||||
struct idt_entry64_struct
|
||||
{
|
||||
uint16_t base_low; // The lower 16 bits of the address to jump to when this interrupt fires.
|
||||
uint16_t sel; // Kernel segment selector.
|
||||
uint8_t always0; // This must always be zero.
|
||||
uint8_t flags; // More flags. See documentation.
|
||||
uint16_t base_high; // The upper 16 bits of the address to jump to.
|
||||
uint32_t base_highest;
|
||||
uint32_t zero1; // Reserved
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct idt_entry32_struct idt_entry32_t;
|
||||
typedef struct idt_entry64_struct idt_entry64_t;
|
||||
#ifdef PLATFORM_X64
|
||||
typedef idt_entry64_t idt_entry_t;
|
||||
#else
|
||||
typedef idt_entry32_t idt_entry_t;
|
||||
#endif
|
||||
|
||||
// A struct describing a pointer to an array of interrupt handlers.
|
||||
// This is in a format suitable for giving to 'lidt'.
|
||||
struct idt_ptr_struct
|
||||
{
|
||||
uint16_t limit;
|
||||
addr_t base; // The address of the first element in our idt_entry_t array.
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct idt_ptr_struct idt_ptr_t;
|
||||
|
||||
void Init();
|
||||
void SetGate(uint8_t num, addr_t base, uint16_t sel, uint8_t flags);
|
||||
void Flush();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue