My Project
Loading...
Searching...
No Matches
meinit.c
Go to the documentation of this file.
1/*++
2
3Module Name:
4
5 meinit.c
6
7Purpose:
8
9 This translation unit contains the implementation of core system init routines (executive).
10
11Author:
12
13 slep (Matanel) 2025.
14
15Revision History:
16
17--*/
18
19#include "../../includes/me.h"
20#include "../../includes/mh.h"
21#include "../../includes/mg.h"
22#include "../../assert.h"
23
24/* Register Bit Definitions */
25#define CR0_MP (1UL << 1) // Monitor Coprocessor
26#define CR0_EM (1UL << 2) // Emulation
27#define CR0_WP (1UL << 16) // Write Protect
28#define CR0_CD (1UL << 30) // Cache Disable
29
30#define CR4_OSFXSR (1UL << 9) // OS FXSAVE/FXRSTOR Support
31#define CR4_OSXMMEXCPT (1UL << 10) // OS Unmasked Exception Support
32#define CR4_UMIP (1UL << 11) // User Mode Instruction Prevention
33#define CR4_FSGSBASE (1UL << 16) // Enable RDFSBASE/RDGSBASE/etc
34#define CR4_SMEP (1UL << 20) // Supervisor Mode Execution Prevention
35#define CR4_SMAP (1UL << 21) // Supervisor Mode Access Prevention
36
37/* CPUID Feature Bits */
38#define CPUID_1_EDX_SSE (1UL << 25)
39#define CPUID_1_EDX_SSE2 (1UL << 26)
40#define CPUID_7_EBX_SMEP (1UL << 7)
41#define CPUID_7_EBX_SMAP (1UL << 20)
42
43
44static void InitialiseControlRegisters(void) {
45 unsigned long cr0 = __read_cr0();
46 unsigned long cr4 = __read_cr4();
47 unsigned int eax, ebx, ecx, edx;
48
49 // Prepare CR0 Configuration
50 cr0 |= CR0_WP; // Write Protect
51#ifdef DISABLE_CACHE
52 cr0 |= CR0_CD; // Cache Disable
53#endif
54
55 // Prepare CR4 Configuration
56 cr4 |= CR4_UMIP; // User Mode Instruction Prevention
57
58 // Clear Debug Registers
59 for (int i = 0; i < 7; i++) __write_dr(i, 0);
60
61 // Detect & Setup SSE/FPU Bits
62 __asm__ volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(1), "c"(0));
63
64 int has_sse = (edx & CPUID_1_EDX_SSE) || (edx & CPUID_1_EDX_SSE2);
65
66 if (has_sse) {
67 cr0 &= ~CR0_EM; // Clear Emulation
68 cr0 |= CR0_MP; // Set Monitor Coprocessor
69 cr4 |= (CR4_OSFXSR | CR4_OSXMMEXCPT); // Enable SSE/Exceptions
70 cr4 |= CR4_FSGSBASE; // Enable FSGSBASE
71 }
72 else {
73 gop_printf(COLOR_RED, "**CPU does not support SSE. Halting.**\n");
74 FREEZE();
75 }
76
77 // Detect & Setup SMAP/SMEP Bits
78 __asm__ volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(7), "c"(0));
79
80 if (ebx & CPUID_7_EBX_SMEP) cr4 |= CR4_SMEP;
81 else gop_printf(COLOR_YELLOW, "SMEP not available.\n");
82
83 if (ebx & CPUID_7_EBX_SMAP) cr4 |= CR4_SMAP;
84 else gop_printf(COLOR_YELLOW, "SMAP not available.\n");
85
86 // COMMIT REGISTERS TO CPU
87 // We MUST write these before executing LDMXCSR below.
88 __write_cr0(cr0);
89 __write_cr4(cr4);
90
91 // Initialize SSE Hardware
92 // Now that CR4.OSFXSR is set in hardware, this instruction is valid.
93 if (has_sse) {
94 unsigned int mxcsr = 0x1f80;
95 __asm__ volatile (
96 "fninit\n\t"
97 "ldmxcsr %0\n\t"
98 : : "m"(mxcsr) : "memory"
99 );
100 }
101}
102
103static void MeInitGdtTssForCurrentProcessor(void) {
105 TSS* tss = cur->tss;
106 uint64_t* gdt = cur->gdt;
107 // gdt is uint64_t gdt[7];
108 gdt[0] = 0;
109 gdt[1] = 0x00AF9A000000FFFF;
110 gdt[2] = 0x00CF92000000FFFF;
111 // user code & data
112 gdt[3] = 0x00AFFA000000FFFF;
113 gdt[4] = 0x00CFF2000000FFFF;
114 uint64_t tss_base = (uint64_t)tss;
115 uint32_t limit = sizeof(TSS) - 1;
116
117 // tss entry
118 kmemset(tss, 0, sizeof(TSS));
119 // Stack and IST's have been moved to MeInitProcessor.
120 tss->io_map_base = sizeof(TSS);
121 tss->rsp0 = (uint64_t)cur->Rsp0;
122 tss->ist[0] = (uint64_t)cur->IstPFStackTop; // IDT.ist = 1
123 tss->ist[1] = (uint64_t)cur->IstDFStackTop; // IDT.ist = 2
124 tss->ist[2] = (uint64_t)cur->IstTimerStackTop; // IDT.ist = 3
125 tss->ist[3] = (uint64_t)cur->IstIpiStackTop; // IDT.ist = 4
126
127 uint64_t tss_limit = (uint64_t)limit; // sizeof(TSS)-1
128 // gdt tss descriptor
129 uint64_t low = (tss_limit & 0xFFFFULL)
130 | ((tss_base & 0xFFFFFFULL) << 16)
131 | (0x89ULL << 40) // P=1, type=0x9 (available 64-bit TSS)
132 | (((tss_limit >> 16) & 0xFULL) << 48) // limit high nibble -> bits 48..51
133 | (((tss_base >> 24) & 0xFFULL) << 56); // base bits 24..31 -> bits 56..63
134
135 // high qword
136 uint64_t high = (tss_base >> 32) & 0xFFFFFFFFULL; // base >> 32 in low 32 bits of high qword
137
138 /* copy two qwords into GDT */
139 gdt[5] = low;
140 gdt[6] = high;
141 const int GDT_ENTRIES = 7;
142
143 GDTPtr gdtr = { .limit = (GDT_ENTRIES * sizeof(uint64_t)) - 1, .base = (uint64_t)gdt };
144 __asm__ volatile("lgdt %0" : : "m"(gdtr));
145 __asm__ volatile(
146 "pushq $0x08\n\t" /* kernel code selector */
147 "leaq 1f(%%rip), %%rax\n\t" /*load ret*/
148 "pushq %%rax\n\t" /*push ret*/
149 "lretq\n\t" /*return*/
150 "1:\n\t"
151 : : : "rax", "memory"
152 );
153
154
155 // tss selector is 16 bit operand
156 unsigned short sel = 0x28; // index 5 * 8
157 __asm__ volatile("ltr %w0" :: "r"(sel));
158}
159
160extern IDT_ENTRY64 IDT[];
161extern IDT_PTR PIDT;
162
163void
165 IN PPROCESSOR CPU,
166 IN bool InitializeStandardRoutine,
167 IN bool AreYouAP
168)
169
170/*++
171
172 Routine description:
173
174 Initializes the current PROCESSOR struct to default values.
175
176 Arguments:
177
178 [IN] PPROCESSOR CPU - Pointer to current PROCESSOR struct.
179 [IN] bool InitializeStandardRoutine - Boolean value indicating if to initialize the TSS & GDT & New IDT of system.
180 [IN] bool AreYouAP - Boolean value indicating the caller of this function is an AP Processor and not the BSP.
181
182 Return Values:
183
184 None.
185
186 Note:
187
188 This routine is ran by every CPU on the system on its startup.
189
190--*/
191
192{
193 if (InitializeStandardRoutine && !AreYouAP) goto StartInit; // If we are BSP, and we want to run the routines, go to them immediately and skip the basic init. If we are AP, we do basic init and start routines anyway.
194 // Initialize the CR registers.
195 InitialiseControlRegisters();
196
197 CPU->self = CPU;
198 CPU->currentIrql = PASSIVE_LEVEL;
199 CPU->schedulerEnabled = NULL; // since NULL is 0, it would be false.
200 CPU->currentThread = NULL;
201 CPU->readyQueue.head = CPU->readyQueue.tail = NULL;
202 // Initialize the DPC Lock & list head.
203 CPU->DpcData.DpcLock.locked = 0;
204 InitializeListHead(&CPU->DpcData.DpcListHead);
205
206 // Initialize DPC Fields.
207 CPU->MaximumDpcQueueDepth = 4; // Baseline.
208 CPU->MinimumDpcRate = 1000; // 1000 DPCs per second baseline (TODO DPC Throttling)
209 CPU->DpcRequestRate = 0; // Initialized to zero.
210 CPU->DpcRoutineActive = false;
211 CPU->DpcInterruptRequested = false;
212 if (!InitializeStandardRoutine && !AreYouAP) return; // If we are BSP, and we do not want to run the routines below, return. If we are AP, we run it none the less.
213
214StartInit: {
215 // Initialize CPU RSP0 and IST Stacks.
216 // RSP0 Is used on anything else that the IST already own.
217 // If we have an IST for IDT 14 (Page Fault), RSP0 will not be taken.
218 // If we don't RSP0 will be taken.
219 // RSP0 Is also taken in syscall instructions, but it is immediately replaced by ITHREAD.KernelStack.
220
221 // Create RSP0 and ISTs for processor.
222 void* Rsp0 = MiCreateKernelStack(false);
223 void* IstPf = MiCreateKernelStack(true);
224 void* IstDf = MiCreateKernelStack(true);
225 void* IstIpi = MiCreateKernelStack(false);
226 void* IstTimer = MiCreateKernelStack(false);
227 bool exists = (IstTimer && IstIpi && IstDf && IstPf && Rsp0) != 0;
228 assert(exists == true);
229 CPU->Rsp0 = Rsp0;
230 CPU->IstPFStackTop = IstPf;
231 CPU->IstDFStackTop = IstDf;
232 CPU->IstIpiStackTop = IstIpi;
233 CPU->IstTimerStackTop = IstTimer;
234
235 // Create new GDT and TSS For Processor.
236 // Allocate TSS.
237 void* tss = MmAllocatePoolWithTag(NonPagedPool, sizeof(TSS), ' ssT'); // If fails on here, check alignment (16 byte)
238 CPU->tss = tss;
239
240 // Allocate GDT.
241 uint64_t* gdt = MmAllocatePoolWithTag(NonPagedPool, sizeof(uint64_t) * 7, ' TDG');
242 CPU->gdt = gdt;
243
244 MeInitGdtTssForCurrentProcessor();
245
246 // ISTs
247 IDT[14].ist = 1; // First one is page fault.
248 IDT[8].ist = 2; // Second one is double fault.
249 IDT[LAPIC_TIMER_VECTOR].ist = 3; // Third one is the LAPIC Timer.
250 IDT[VECTOR_IPI].ist = 4; // Fourth one is the LAPIC IPI.
251
252 // Reload IDT with set stacks.
253 __lidt(&PIDT);
254 }
255}
#define IN
Definition annotations.h:7
#define assert(...)
Definition assert.h:57
@ PASSIVE_LEVEL
Definition core.h:13
PROCESSOR * PPROCESSOR
Definition core.h:46
void gop_printf(uint32_t color, const char *fmt,...)
Definition gop.c:694
FORCEINLINE unsigned long int __read_cr0(void)
Definition intrin.h:55
FORCEINLINE void __write_cr0(unsigned long int val)
Definition intrin.h:62
FORCEINLINE void __write_cr4(unsigned long val)
Definition intrin.h:93
FORCEINLINE void __write_dr(int reg, uint64_t val)
Definition intrin.h:124
FORCEINLINE unsigned long __read_cr4(void)
Definition intrin.h:88
FORCEINLINE void __lidt(void *idt_ptr)
Definition intrin.h:135
#define FREEZE()
Definition macros.h:49
FORCEINLINE PPROCESSOR MeGetCurrentProcessor(void)
Definition me.h:356
#define CR4_SMAP
Definition meinit.c:35
#define CR0_WP
Definition meinit.c:27
#define CR0_MP
Definition meinit.c:25
#define CR0_EM
Definition meinit.c:26
#define CR4_OSXMMEXCPT
Definition meinit.c:31
IDT_PTR PIDT
Definition idt.c:10
#define CR4_FSGSBASE
Definition meinit.c:33
#define CPUID_7_EBX_SMEP
Definition meinit.c:40
#define CPUID_1_EDX_SSE2
Definition meinit.c:39
#define CR4_SMEP
Definition meinit.c:34
#define CPUID_1_EDX_SSE
Definition meinit.c:38
void MeInitializeProcessor(IN PPROCESSOR CPU, IN bool InitializeStandardRoutine, IN bool AreYouAP)
Definition meinit.c:164
#define CPUID_7_EBX_SMAP
Definition meinit.c:41
IDT_ENTRY64 IDT[]
Definition idt.c:9
#define CR4_OSFXSR
Definition meinit.c:30
#define CR0_CD
Definition meinit.c:28
#define CR4_UMIP
Definition meinit.c:32
#define COLOR_YELLOW
Definition mg.h:34
#define COLOR_RED
Colors definitions for easier access.
Definition mg.h:29
struct _IDT_PTR IDT_PTR
struct _IDT_ENTRY_64 IDT_ENTRY64
TSS
Definition mh.h:383
#define VECTOR_IPI
Definition mh.h:49
#define LAPIC_TIMER_VECTOR
Definition mh.h:50
GDTPtr
Definition mh.h:371
@ NonPagedPool
Definition mm.h:316
FORCEINLINE void * kmemset(void *dest, int64_t val, uint64_t len)
Definition mm.h:540
void * MiCreateKernelStack(IN bool LargeStack)
Definition mmproc.c:25
FORCEINLINE void InitializeListHead(PDOUBLY_LINKED_LIST Head)
Definition ms.h:166
void * MmAllocatePoolWithTag(IN enum _POOL_TYPE PoolType, IN size_t NumberOfBytes, IN uint32_t Tag)
Definition pool.c:427
uint64_t * gdt
Definition me.h:289
void * Rsp0
Definition me.h:284
void * tss
Definition me.h:283
void * IstPFStackTop
Definition me.h:285