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