The Pedigree Project 0.1
gdt.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "gdt.h"
21#include "pedigree/kernel/Log.h"
22#include "pedigree/kernel/processor/Processor.h"
23#include "pedigree/kernel/processor/ProcessorInformation.h"
24#include "pedigree/kernel/processor/x64/tss.h"
25#include "pedigree/kernel/stddef.h"
26#include "pedigree/kernel/utilities/Vector.h"
27#include "pedigree/kernel/utilities/utility.h"
28
29#include "InterruptManager.h"
30
31namespace {
32struct alignas(16) ExceptionStack {
33 uint8_t bytes[8192];
34};
35static_assert(offsetof(X64TaskStateSegment, ist) == 0x24, "IST1 must be at TSS offset 0x24");
36static_assert(sizeof(ExceptionStack) % 16 == 0, "IST stack top must be aligned");
37} // namespace
38
40
41void X64GdtManager::initialise(size_t processorCount) {
42 // Calculate the number of entries
43 m_DescriptorCount = 7 + 2 * processorCount;
44
45 // Allocate the GDT
47
48 // Fill the GDT
49 setSegmentDescriptor(0, 0, 0, 0, 0);
50 setSegmentDescriptor(1, 0, 0, 0x98, 0x2); // Kernel code - 0x08
51 setSegmentDescriptor(2, 0, 0, 0x92, 0x2); // Kernel data - 0x10
52 setSegmentDescriptor(3, 0, 0, 0xF8, 0x2); // User code32 - 0x18
53 setSegmentDescriptor(4, 0, 0, 0xF2, 0x2); // User data32 - 0x20
54 setSegmentDescriptor(5, 0, 0, 0xF8, 0x22); // User code64 - 0x28
55 setSegmentDescriptor(6, 0, 0, 0xF2, 0x22); // User data64 - 0x30
56
57#if MULTIPROCESSOR
58
59 size_t i = 0;
61 it != Processor::m_ProcessorInformation.end(); it++, i += 2) {
62 NOTICE("Setting up TSS segment for CPU #" << Dec << i << Hex << ".");
63
65 initialiseTss(Tss);
66 setTssDescriptor(i + 7, reinterpret_cast<uint64_t>(Tss));
67
68 ProcessorInformation* processorInfo = *it;
69 processorInfo->setTss(Tss);
70 processorInfo->setTssSelector((i + 7) << 3);
71 processorInfo->setTlsSelector((i + 8) << 3);
72 }
73#else
74
76 initialiseTss(Tss);
77 setTssDescriptor(7, reinterpret_cast<uint64_t>(Tss));
78
79 ProcessorInformation& processorInfo = Processor::information();
80 processorInfo.setTss(Tss);
81 processorInfo.setTssSelector(7 << 3);
82 processorInfo.setTlsSelector(8 << 3);
83#endif
84}
85
87 struct {
88 uint16_t size;
89 uint64_t gdt;
90 } PACKED gdtr;
91
92 gdtr.size = (m_Instance.m_DescriptorCount * 8) - 1;
93 gdtr.gdt = reinterpret_cast<uint64_t>(m_Instance.m_Gdt);
94
95 asm volatile("lgdt %0" ::"m"(gdtr));
96 asm volatile("ltr %%ax" ::"a"(Processor::information().getTssSelector()));
97
100}
101
102X64GdtManager::X64GdtManager() : m_Gdt(0), m_DescriptorCount(0) {}
104
105void X64GdtManager::setSegmentDescriptor(size_t index, uint64_t base, uint32_t limit, uint8_t flags,
106 uint8_t flags2) {
107 m_Gdt[index].limit0 = limit & 0xFFFF;
108 m_Gdt[index].base0 = base & 0xFFFF;
109 m_Gdt[index].base1 = (base >> 16) & 0xFF;
110 m_Gdt[index].flags = flags;
111 m_Gdt[index].flags_limit1 = ((flags2 & 0x0F) << 4) | ((limit >> 16) & 0x0F);
112 m_Gdt[index].base2 = (base >> 24) & 0xFF;
113}
114void X64GdtManager::setTssDescriptor(size_t index, uint64_t base) {
115 setSegmentDescriptor(index, base & 0xFFFFFFFF, sizeof(X64TaskStateSegment), 0x89, 0x00);
116 tss_descriptor* Tss = reinterpret_cast<tss_descriptor*>(&m_Gdt[index + 1]);
117 Tss->base3 = (base >> 32) & 0xFFFFFFFF;
118 Tss->res = 0;
119}
121 ByteSet(reinterpret_cast<void*>(pTss), 0, sizeof(X64TaskStateSegment));
122
123 // Each permanent TSS needs its own resident stack: simultaneous faults must
124 // not overwrite another CPU's frame. Touch every page before emergency use.
125 // Match the independent #DF/NMI/#DB/#MC/#GP/#SS entries in the permanent IDT.
126 // The IDT's IST selector is one-based, while the TSS array is zero-based.
127 for (size_t i = 0; i < 6; ++i) {
128 auto* stack = new ExceptionStack{};
129 pTss->ist[i] = reinterpret_cast<uint64_t>(stack + 1);
130 }
131
132 // All entries will be zero by default (all ports accessible to all IOPLs)
134 pTss->ioPermBitmap = offsetof(X64TaskStateSegment, ioPermBitmapData);
135}
136
137void X64GdtManager::initialiseDoubleFaultTss(X64TaskStateSegment* pTss) {
138 // IST used on amd64
139}
static ProcessorInformation & information()
static Vector< ProcessorInformation * > m_ProcessorInformation
Definition Processor.h:504
Iterator end()
Definition Vector.h:172
~X64GdtManager()
Definition gdt.cc:103
X64GdtManager() INITIALISATION_ONLY
Definition gdt.cc:102
segment_descriptor * m_Gdt
Definition gdt.h:109
void setSegmentDescriptor(size_t index, uint64_t base, uint32_t limit, uint8_t flags, uint8_t flags2)
Definition gdt.cc:105
void initialise(size_t processorCount) INITIALISATION_ONLY
Definition gdt.cc:41
static X64GdtManager m_Instance
Definition gdt.h:114
size_t m_DescriptorCount
Definition gdt.h:111
static void loadSegmentRegisters()
static void initialiseProcessor() INITIALISATION_ONLY
Definition gdt.cc:86
void initialiseTss(X64TaskStateSegment *pTss) INITIALISATION_ONLY
Definition gdt.cc:120
void setTssDescriptor(size_t index, uint64_t base) INITIALISATION_ONLY
Definition gdt.cc:114
static void initialiseProcessorIst() INITIALISATION_ONLY
@ Dec
Definition Log.h:144
@ Hex
Definition Log.h:142