The Pedigree Project  0.1
x86/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/processor/Processor.h"
22 #include "pedigree/kernel/processor/VirtualAddressSpace.h"
23 #include "pedigree/kernel/utilities/utility.h"
24 
26 
27 // These will all be safe for use when entering a double fault handler
28 static char g_SafeStack[8192] = {0};
29 
30 void X86GdtManager::initialise(size_t processorCount)
31 {
32  // Calculate the number of entries
33  m_DescriptorCount = 6 + (processorCount * 2);
34 
35  // Allocate the GDT
37 
38  // Fill the GDT
39  setSegmentDescriptor(0, 0, 0, 0, 0);
40  setSegmentDescriptor(1, 0, 0xFFFFF, 0x98, 0xC); // Kernel code - 0x08
41  setSegmentDescriptor(2, 0, 0xFFFFF, 0x92, 0xC); // Kernel data - 0x10
42  setSegmentDescriptor(3, 0, 0xFFFFF, 0xF8, 0xC); // User code - 0x18
43  setSegmentDescriptor(4, 0, 0xFFFFF, 0xF2, 0xC); // User data - 0x20
44 
45 #ifdef MULTIPROCESSOR
46 
48 
49  size_t i = 0;
52  it != Processor::m_ProcessorInformation.end(); it++, i += 2)
53  {
54  NOTICE("Setting up TSS segment for CPU #" << Dec << i << Hex << ".");
55 
57  initialiseTss(Tss);
58  setTssDescriptor(i + 5, reinterpret_cast<uint32_t>(Tss));
59 
60  ProcessorInformation *processorInfo = *it;
61  processorInfo->setTss(Tss);
62  processorInfo->setTssSelector((i + 5) << 3);
63 
64  // TLS segment
65  setSegmentDescriptor(i + 6, 0, 0xFFFFF, 0xF2, 0xC);
66  processorInfo->setTlsSelector((i + 6) << 3);
67  }
68 #else
69  setSegmentDescriptor(6, 0, 0xFFFFF, 0xF2, 0xC); // User TLS data - 0x30
70 
72  initialiseTss(Tss);
73  setTssDescriptor(5, reinterpret_cast<uint32_t>(Tss)); // 0x28
74 
75  ProcessorInformation &processorInfo = Processor::information();
76  processorInfo.setTss(Tss);
77  processorInfo.setTssSelector(5 << 3);
78  processorInfo.setTlsSelector(6 << 3);
79 
80  // Create the double-fault handler TSS
81  static X86TaskStateSegment DFTss;
83  setTssDescriptor(7, reinterpret_cast<uint32_t>(&DFTss)); // 0x38
84 #endif
85 }
87 {
88  struct
89  {
90  uint16_t size;
91  uint32_t gdt;
92  } PACKED gdtr = {
93  static_cast<uint16_t>((m_Instance.m_DescriptorCount * 8 - 1) & 0xFFFF),
94  reinterpret_cast<uintptr_t>(m_Instance.m_Gdt)};
95 
96  asm volatile("lgdt %0" ::"m"(gdtr));
97  asm volatile("ltr %%ax" ::"a"(Processor::information().getTssSelector()));
98 
99  // Flush the segment registers (until now we're running with the ones the
100  // Multiboot loader set us up with, which, when we *reload* them, may not be
101  // valid in the new GDT)
102  asm volatile("jmp $0x8, $.flush; \
103  .flush: \
104  mov $0x10, %ax; \
105  mov %ax, %ds; \
106  mov %ax, %es; \
107  mov %ax, %fs; \
108  mov %ax, %gs; \
109  mov %ax, %ss;");
110 }
111 
113 {
114 }
116 {
117 }
118 
119 void X86GdtManager::setTlsBase(uintptr_t base)
120 {
121 #ifdef MULTIPROCESSOR
124  Processor::information().getTlsSelector() >> 3, base, 0xFFFFF, 0xF2,
125  0xC);
126 #else
127  setSegmentDescriptor(6, base, 0xFFFFF, 0xF2, 0xC); // User TLS data - 0x28
128 #endif
129 }
130 
132  size_t index, uint32_t base, uint32_t limit, uint8_t flags, uint8_t flags2)
133 {
134  m_Gdt[index].limit0 = limit & 0xFFFF;
135  m_Gdt[index].base0 = base & 0xFFFF;
136  m_Gdt[index].base1 = (base >> 16) & 0xFF;
137  m_Gdt[index].flags = flags;
138  m_Gdt[index].flags_limit1 = ((flags2 & 0x0F) << 4) | ((limit >> 16) & 0x0F);
139  m_Gdt[index].base2 = (base >> 24) & 0xFF;
140 }
141 void X86GdtManager::setTssDescriptor(size_t index, uint32_t base)
142 {
143  setSegmentDescriptor(index, base, sizeof(X86TaskStateSegment), 0x89, 0x00);
144 }
146 {
147  ByteSet(reinterpret_cast<void *>(pTss), 0, sizeof(X86TaskStateSegment));
148  pTss->ss0 = 0x10;
149 }
150 
152 {
153  uint32_t offset : 12;
154  uint32_t tbl : 10;
155  uint32_t dir : 10;
156 } __attribute__((packed));
157 
159 {
160  // All our interrupt handlers - the TSS will hook into the DF handler, and
161  // the entry point
162  extern uintptr_t interrupt_handler_array[];
163  extern void start();
164 
165  ByteSet(reinterpret_cast<void *>(pTss), 0, sizeof(X86TaskStateSegment));
166 
167  // Stack - set to the statically allocated stack (mapped later)
168  pTss->ss0 = pTss->ss = 0x10;
169  pTss->esp0 = pTss->esp = pTss->esp1 = pTss->esp2 =
170  reinterpret_cast<uint32_t>(g_SafeStack) + 8192;
171 
172  // When the fault occurs, jump to the ISR handler (so it'll automatically
173  // jump to the common ISR handler)
174  pTss->eip = static_cast<uint32_t>(interrupt_handler_array[8]);
175 
176  // Set up the segments
177  pTss->ds = pTss->es = pTss->fs = pTss->gs = 0x10;
178  pTss->cs = 0x08;
179 
180 // Grab the kernel address space and clone it
184 #if 0
186  NOTICE("CR3 1 = " << Processor::readCr3());
187  Processor::switchAddressSpace(*dfAddressSpace);
188  NOTICE("CR3 2 = " << Processor::readCr3());
189  pTss->cr3 = Processor::readCr3();
191 #else
192  pTss->cr3 = Processor::readCr3();
193 #endif
194 }
static X86GdtManager m_Instance
Definition: x86/gdt.h:107
static void initialiseProcessor() INITIALISATION_ONLY
Definition: x86/gdt.cc:86
static EXPORTED_PUBLIC VirtualAddressSpace & getKernelAddressSpace()
static ProcessorInformation & information()
Definition: Processor.cc:45
static void switchAddressSpace(VirtualAddressSpace &AddressSpace)
void setTssDescriptor(size_t index, uint32_t base) INITIALISATION_ONLY
Definition: x86/gdt.cc:141
void setTlsBase(uintptr_t base)
Definition: x86/gdt.cc:119
void initialiseTss(struct X86TaskStateSegment *pTss) INITIALISATION_ONLY
Definition: x86/gdt.cc:145
void initialise(size_t processorCount) INITIALISATION_ONLY
Definition: x86/gdt.cc:30
#define NOTICE(text)
Definition: Log.h:74
Definition: Log.h:136
T * Iterator
Definition: Vector.h:37
X86GdtManager() INITIALISATION_ONLY
Definition: x86/gdt.cc:112
void initialiseDoubleFaultTss(X86TaskStateSegment *pTss) INITIALISATION_ONLY
Definition: x86/gdt.cc:158
size_t m_DescriptorCount
Definition: x86/gdt.h:104
Definition: Log.h:138
static ProcessorInformation m_ProcessorInformation
Definition: Processor.h:386
virtual VirtualAddressSpace * clone(bool copyOnWrite=true)=0
void setSegmentDescriptor(size_t index, uint32_t base, uint32_t limit, uint8_t flags, uint8_t flags2)
Definition: x86/gdt.cc:131
segment_descriptor * m_Gdt
Definition: x86/gdt.h:102