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/process/initialiseMultitasking.h"
21#include "pedigree/kernel/processor/IoPortManager.h"
22#include "pedigree/kernel/processor/NMFaultHandler.h"
23#include "pedigree/kernel/processor/PageFaultHandler.h"
24#include "pedigree/kernel/processor/Processor.h"
25#include "pedigree/kernel/processor/state.h"
26#include "pedigree/kernel/utilities/utility.h"
27
28#include "../x86_common/Multiprocessor.h"
29#include "../x86_common/PhysicalMemoryManager.h"
30#include "InterruptManager.h"
31#include "SyscallManager.h"
32#include "VirtualAddressSpace.h"
33#include "gdt.h"
34
35#define PAT_UC 0x00
36#define PAT_WC 0x01
37#define PAT_WT 0x04
38#define PAT_WP 0x05
39#define PAT_WB 0x06
40#define PAT_UCMINUS 0x07
41
42constinit ProcessorInformation::KernelGsAnchor ProcessorBase::m_BootstrapKernelGsAnchor = {
43 0, 0, &m_SafeBspProcessorInformation, 0, nullptr};
44
45union pat {
46 struct {
47 uint32_t pa0 : 3;
48 uint32_t rsvd0 : 5;
49 uint32_t pa1 : 3;
50 uint32_t rsvd1 : 5;
51 uint32_t pa2 : 3;
52 uint32_t rsvd2 : 5;
53 uint32_t pa3 : 3;
54 uint32_t rsvd3 : 5;
55 uint32_t pa4 : 3;
56 uint32_t rsvd4 : 5;
57 uint32_t pa5 : 3;
58 uint32_t rsvd5 : 5;
59 uint32_t pa6 : 3;
60 uint32_t rsvd6 : 5;
61 uint32_t pa7 : 3;
62 uint32_t rsvd7 : 5;
63 } s;
64 uint64_t x;
65};
66
67static int doInitialise64(const BootstrapStruct_t& info) {
68 // Initialise the 64-bit physical memory management
69 // This could be done in parallel with system startup, as other parts of
70 // the system that *need* pages above 4GB will be able to block until they
71 // are available, and otherwise page allocations will be adequately
72 // completed by the presence of pages under 4GB.
73 X86CommonPhysicalMemoryManager& physicalMemoryManager =
75 physicalMemoryManager.initialise64(info);
76
77 return 0;
78}
79
81 X64VirtualAddressSpace& x64AddressSpace = static_cast<X64VirtualAddressSpace&>(AddressSpace);
82 const bool restoreInterrupts = getInterrupts();
83 setInterrupts(false);
84
85 // Get the current page directory
86 uint64_t cr3;
87 asm volatile("mov %%cr3, %0" : "=r"(cr3));
88
89 // Do we need to set a new page directory?
90 if (cr3 != x64AddressSpace.m_PhysicalPML4) {
91 ProcessorInformation& processorInformation = Processor::information();
92 X64VirtualAddressSpace& previous =
93 static_cast<X64VirtualAddressSpace&>(processorInformation.getVirtualAddressSpace());
94 const size_t processor = Processor::index();
95 const uint64_t bit = processor < 64 ? uint64_t(1) << processor : 0;
96
97 // Publish before loading any private translation. Keep the outgoing bit
98 // until CR3 has flushed it. No PCIDs or global lower-half leaves survive
99 // this switch, so an invalidator can safely omit CPUs outside the mask.
100 x64AddressSpace.m_ResidentProcessors |= bit;
101 asm volatile("mov %0, %%cr3" ::"r"(x64AddressSpace.m_PhysicalPML4) : "memory");
102 processorInformation.setVirtualAddressSpace(AddressSpace);
103 previous.m_ResidentProcessors &= ~bit;
104 }
105 setInterrupts(restoreInterrupts);
106}
107
109 shutdownMultitasking();
110
111 // Release physical-memory bookkeeping only after every runtime owner has
112 // been terminally quiesced. Terminal bare-metal shutdown retains static
113 // storage; nothing may consume PMM state after this point.
115}
116
118 // Global constructors have completed; retire the constructor-independent anchor.
119 m_SafeBspProcessorInformation.activateKernelGsAnchor(0);
120
121 // Initialise this processor's interrupt handling
123
124 // Initialise this processor's syscall handling
126
127 // Enable Write-Protect so the kernel can write to CoW pages and not break
128 // that contract.
129 asm volatile("mov %%cr0, %%rax; or $0x10000, %%rax; mov %%rax, %%cr0" ::: "rax");
130
132
133 // Initialise the physical memory-management
134 X86CommonPhysicalMemoryManager& physicalMemoryManager =
136 physicalMemoryManager.initialise(Info);
137
138 // Initialise the I/O Manager
139 IoPortManager& ioPortManager = IoPortManager::instance();
140 ioPortManager.initialise(0, 0x10000);
141
142 // Initialise floating point.
145
147 // Write PAT MSR.
148 // MSR 0x277
149
150 /*
151 PAT Entry
152 Memory Type Following Power-up or Reset
153 PAT0 WB
154 PAT1 WT
155 PAT2 UC-
156 PAT3 UC
157 PAT4 WB
158 PAT5 WT
159 PAT6 UC-
160 PAT7 UC
161 */
162 //
163 uint32_t pat_lo, pat_hi;
164 asm volatile("rdmsr" : "=a"(pat_lo), "=d"(pat_hi) : "c"(0x277));
165
166 union pat p;
167 p.x = pat_lo | (static_cast<uint64_t>(pat_hi) << 32ULL);
168 p.s.pa0 = PAT_WB;
169 p.s.pa1 = PAT_WC; // Redefine PWT in all page entries to mean WC instead of WT.
170 p.s.pa2 = PAT_UCMINUS;
171 p.s.pa3 = PAT_UC;
172 p.s.pa4 = PAT_WB;
173 p.s.pa5 = PAT_WT; // PWT|PAT == WT.
174 p.s.pa6 = PAT_UCMINUS;
175 p.s.pa7 = PAT_UC;
176 pat_lo = static_cast<uint32_t>(p.x);
177 pat_hi = static_cast<uint32_t>(p.x >> 32ULL);
178
179 asm volatile("wrmsr" ::"a"(pat_lo), "d"(pat_hi), "c"(0x277));
180
181 m_Initialised = 1;
182}
183
185 size_t nProcessors = 1;
186
187 EMIT_IF(MULTIPROCESSOR) {
188 nProcessors = Multiprocessor::initialise1();
189 }
190
191 // Initialise the GDT
192 X64GdtManager::instance().initialise(nProcessors);
194
195 initialiseMultitasking();
196
197 doInitialise64(Info);
198
199 m_Initialised = 2;
200
201 EMIT_IF(MULTIPROCESSOR) {
202 if (nProcessors != 1)
204 }
205}
206
208 uint32_t eax, ebx, ecx, edx;
209 char ident[13];
210 X86CommonProcessor::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
218void ProcessorBase::setTlsBase(uintptr_t newBase) {
219 pedigree_materialize_user_entry();
220 // Set FS.base MSR.
221 asm volatile("wrmsr" ::"a"(newBase), "d"(newBase >> 32ULL), "c"(0xC0000100));
222}
223
224uintptr_t ProcessorBase::getUserGsBase() {
225 uint32_t low, high;
226 asm volatile("rdmsr" : "=a"(low), "=d"(high) : "c"(0xc0000102) : "memory");
227 return low | (static_cast<uintptr_t>(high) << 32);
228}
229
230void ProcessorBase::setUserGsBase(uintptr_t newBase) {
231 pedigree_materialize_user_entry();
232 asm volatile("wrmsr"
233 :
234 : "a"(static_cast<uint32_t>(newBase)), "d"(static_cast<uint32_t>(newBase >> 32)),
235 "c"(0xc0000102)
236 : "memory");
237}
Manages hardware I/O port (de)allocations.
void initialise(io_port_t ioPortBase, size_t size) INITIALISATION_ONLY
static IoPortManager & instance()
static size_t initialise1() INITIALISATION_ONLY
static void initialise2() INITIALISATION_ONLY
static NMFaultHandler & instance()
bool initialiseProcessor()
static PageFaultHandler & instance()
static bool getInterrupts()
static void initialise2(const BootstrapStruct_t &Info) INITIALISATION_ONLY
second/last stage in the initialisation of the processor-specific interface
static void setTlsBase(uintptr_t newBase)
static void initialise1(const BootstrapStruct_t &Info) INITIALISATION_ONLY
first stage in the initialisation of the processor-specific interface
static ProcessorInformation & information()
static void identify(HugeStaticString &str)
static size_t m_Initialised
Definition Processor.h:483
static void switchAddressSpace(VirtualAddressSpace &AddressSpace)
static ProcessorInformation m_SafeBspProcessorInformation
Definition Processor.h:516
static void setInterrupts(bool bEnable)
static void deinitialise()
static size_t index()
static X64GdtManager & instance()
Definition gdt.h:37
void initialise(size_t processorCount) INITIALISATION_ONLY
Definition gdt.cc:41
static void initialiseProcessor() INITIALISATION_ONLY
Definition gdt.cc:86
static void initialiseProcessor() INITIALISATION_ONLY
static void initialiseProcessor() INITIALISATION_ONLY
Implementation of the PhysicalMemoryManager for common x86.
void initialise64(const BootstrapStruct_t &Info) INITIALISATION_ONLY
void initialise(const BootstrapStruct_t &Info) INITIALISATION_ONLY
static void cpuid(uint32_t inEax, uint32_t inEcx, uint32_t &eax, uint32_t &ebx, uint32_t &ecx, uint32_t &edx)