The Pedigree Project  0.1
x64/Processor.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 "pedigree/kernel/processor/Processor.h"
21 #include "../x86_common/PhysicalMemoryManager.h"
22 #include "InterruptManager.h"
23 #include "SyscallManager.h"
24 #include "VirtualAddressSpace.h"
25 #include "gdt.h"
26 #include "pedigree/kernel/process/initialiseMultitasking.h"
27 #include "pedigree/kernel/processor/IoPortManager.h"
28 #include "pedigree/kernel/processor/NMFaultHandler.h"
29 #include "pedigree/kernel/processor/PageFaultHandler.h"
30 #include "pedigree/kernel/utilities/utility.h"
31 
32 // Multiprocessor headers
33 #if defined(MULTIPROCESSOR)
34 #include "../x86_common/Multiprocessor.h"
35 #endif
36 
37 #define PAT_UC 0x00
38 #define PAT_WC 0x01
39 #define PAT_WT 0x04
40 #define PAT_WP 0x05
41 #define PAT_WB 0x06
42 #define PAT_UCMINUS 0x07
43 
44 union pat
45 {
46  struct
47  {
48  uint32_t pa0 : 3;
49  uint32_t rsvd0 : 5;
50  uint32_t pa1 : 3;
51  uint32_t rsvd1 : 5;
52  uint32_t pa2 : 3;
53  uint32_t rsvd2 : 5;
54  uint32_t pa3 : 3;
55  uint32_t rsvd3 : 5;
56  uint32_t pa4 : 3;
57  uint32_t rsvd4 : 5;
58  uint32_t pa5 : 3;
59  uint32_t rsvd5 : 5;
60  uint32_t pa6 : 3;
61  uint32_t rsvd6 : 5;
62  uint32_t pa7 : 3;
63  uint32_t rsvd7 : 5;
64  } s;
65  uint64_t x;
66 };
67 
68 static int doInitialise64(const BootstrapStruct_t &info)
69 {
70  // Initialise the 64-bit physical memory management
71  // This could be done in parallel with system startup, as other parts of
72  // the system that *need* pages above 4GB will be able to block until they
73  // are available, and otherwise page allocations will be adequately
74  // completed by the presence of pages under 4GB.
75  X86CommonPhysicalMemoryManager &physicalMemoryManager =
77  physicalMemoryManager.initialise64(info);
78 
79  return 0;
80 }
81 
83 {
84  const X64VirtualAddressSpace &x64AddressSpace =
85  static_cast<const X64VirtualAddressSpace &>(AddressSpace);
86 
87  // Get the current page directory
88  uint64_t cr3;
89  asm volatile("mov %%cr3, %0" : "=r"(cr3));
90 
91  // Do we need to set a new page directory?
92  if (cr3 != x64AddressSpace.m_PhysicalPML4)
93  {
94  // Set the new page directory
95  asm volatile("mov %0, %%cr3" ::"r"(x64AddressSpace.m_PhysicalPML4));
96 
97  // Update the information in the ProcessorInformation structure
98  ProcessorInformation &processorInformation = Processor::information();
99  processorInformation.setVirtualAddressSpace(AddressSpace);
100  }
101 }
102 
104 {
105  shutdownMultitasking();
106 
107  // Shut down remaining singleton objects.
110  PageFaultHandler::instance().~PageFaultHandler();
113 }
114 
116 {
117  // Initialise this processor's interrupt handling
119 
120  // Initialise this processor's syscall handling
122 
123  // Enable Write-Protect so the kernel can write to CoW pages and not break
124  // that contract.
125  asm volatile("mov %%cr0, %%rax; or $0x10000, %%rax; mov %%rax, %%cr0" ::
126  : "rax");
127 
129 
130  // Initialise the physical memory-management
131  X86CommonPhysicalMemoryManager &physicalMemoryManager =
133  physicalMemoryManager.initialise(Info);
134 
135  // Initialise the I/O Manager
136  IoPortManager &ioPortManager = IoPortManager::instance();
137  ioPortManager.initialise(0, 0x10000);
138 
139  // Initialise floating point.
142 
144  // Write PAT MSR.
145  // MSR 0x277
146 
147  /*
148  PAT Entry
149  Memory Type Following Power-up or Reset
150  PAT0 WB
151  PAT1 WT
152  PAT2 UC-
153  PAT3 UC
154  PAT4 WB
155  PAT5 WT
156  PAT6 UC-
157  PAT7 UC
158  */
159  //
160  uint32_t pat_lo, pat_hi;
161  asm volatile("rdmsr" : "=a"(pat_lo), "=d"(pat_hi) : "c"(0x277));
162 
163  union pat p;
164  p.x = pat_lo | (static_cast<uint64_t>(pat_hi) << 32ULL);
165  p.s.pa0 = PAT_WB;
166  p.s.pa1 =
167  PAT_WC; // Redefine PWT in all page entries to mean WC instead of WT.
168  p.s.pa2 = PAT_UCMINUS;
169  p.s.pa3 = PAT_UC;
170  p.s.pa4 = PAT_WB;
171  p.s.pa5 = PAT_WT; // PWT|PAT == WT.
172  p.s.pa6 = PAT_UCMINUS;
173  p.s.pa7 = PAT_UC;
174  pat_lo = static_cast<uint32_t>(p.x);
175  pat_hi = static_cast<uint32_t>(p.x >> 32ULL);
176 
177  asm volatile("wrmsr" ::"a"(pat_lo), "d"(pat_hi), "c"(0x277));
178 
179  m_Initialised = 1;
180 }
181 
183 {
184 #if defined(MULTIPROCESSOR)
185  size_t nProcessors = Multiprocessor::initialise1();
186 #else
187  size_t nProcessors = 1;
188 #endif
189 
190  // Initialise the GDT
191  X64GdtManager::instance().initialise(nProcessors);
193 
194  initialiseMultitasking();
195 
196  doInitialise64(Info);
197 
198  m_Initialised = 2;
199 
200 #if defined(MULTIPROCESSOR)
201  if (nProcessors != 1)
203 #endif
204 }
205 
207 {
208  uint32_t eax, ebx, ecx, edx;
209  char ident[13];
210  cpuid(0, 0, eax, ebx, ecx, edx);
211  MemoryCopy(ident, &ebx, 4);
212  MemoryCopy(&ident[4], &edx, 4);
213  MemoryCopy(&ident[8], &ecx, 4);
214  ident[12] = 0;
215  str = ident;
216 }
217 
218 void Processor::setTlsBase(uintptr_t newBase)
219 {
220  // Set FS.base MSR.
221  asm volatile(
222  "wrmsr" ::"a"(newBase), "d"(newBase >> 32ULL), "c"(0xC0000100));
223 }
Bootstrap structure passed to the kernel entry point.
static void setTlsBase(uintptr_t newBase)
static X64GdtManager & instance()
Definition: x64/gdt.h:37
static void initialise2(const BootstrapStruct_t &Info) INITIALISATION_ONLY
second/last stage in the initialisation of the processor-specific interface
static IoPortManager & instance()
Definition: IoPortManager.h:44
void initialise(size_t processorCount) INITIALISATION_ONLY
Definition: x64/gdt.cc:35
static ProcessorInformation & information()
Definition: Processor.cc:45
void initialise64(const BootstrapStruct_t &Info) INITIALISATION_ONLY
static void switchAddressSpace(VirtualAddressSpace &AddressSpace)
virtual ~IoPortManager()
Manages hardware I/O port (de)allocations.
Definition: IoPortManager.h:38
static PageFaultHandler & instance()
static size_t initialise1() INITIALISATION_ONLY
void initialise(io_port_t ioPortBase, size_t size) INITIALISATION_ONLY
static void initialise1(const BootstrapStruct_t &Info) INITIALISATION_ONLY
first stage in the initialisation of the processor-specific interface
static void initialise2() INITIALISATION_ONLY
static X64SyscallManager & instance()
static NMFaultHandler & instance()
static void deinitialise()
static void identify(HugeStaticString &str)
static void initialiseProcessor() INITIALISATION_ONLY
static void initialiseProcessor() INITIALISATION_ONLY
void initialise(const BootstrapStruct_t &Info) INITIALISATION_ONLY
Implementation of the PhysicalMemoryManager for common x86.
static void initialiseProcessor() INITIALISATION_ONLY
Definition: x64/gdt.cc:85
static X64InterruptManager & instance()