Release the dispatcher lock after KiUnblockThread.
[reactos.git] / reactos / ntoskrnl / ke / main.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ke/main.c
5 * PURPOSE: Initalizes the kernel
6 *
7 * PROGRAMMERS: Alex Ionescu (cleaned up code, moved Executiv stuff to ex/init.c)
8 * David Welch (welch@cwcom.net)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* GLOBALS *******************************************************************/
18
19 #define BUILD_OSCSDVERSION(major, minor) (((major & 0xFF) << 8) | (minor & 0xFF))
20
21
22 ULONG NtMajorVersion = 5;
23 ULONG NtMinorVersion = 0;
24 ULONG NtOSCSDVersion = BUILD_OSCSDVERSION(4, 0);
25 ULONG NtBuildNumber = KERNEL_VERSION_BUILD;
26 ULONG NtGlobalFlag = 0;
27 CHAR KeNumberProcessors;
28 KAFFINITY KeActiveProcessors = 1;
29 LOADER_PARAMETER_BLOCK KeLoaderBlock;
30 ULONG KeDcacheFlushCount = 0;
31 ULONG KeIcacheFlushCount = 0;
32 ULONG KiDmaIoCoherency = 0; /* RISC Architectures only */
33 ULONG InitSafeBootMode = 0; /* KB83764 */
34
35 LOADER_MODULE KeLoaderModules[64];
36 static CHAR KeLoaderModuleStrings[64][256];
37 static CHAR KeLoaderCommandLine[256];
38 ADDRESS_RANGE KeMemoryMap[64];
39 ULONG KeMemoryMapRangeCount;
40 ULONG_PTR FirstKrnlPhysAddr;
41 ULONG_PTR LastKrnlPhysAddr;
42 ULONG_PTR LastKernelAddress;
43
44 PVOID KeUserApcDispatcher = NULL;
45 PVOID KeUserCallbackDispatcher = NULL;
46 PVOID KeUserExceptionDispatcher = NULL;
47 PVOID KeRaiseUserExceptionDispatcher = NULL;
48
49 ULONG KeLargestCacheLine = 0x40; /* FIXME: Arch-specific */
50
51 /* We allocate 4 pages, but we only use 3. The 4th is to guarantee page alignment */
52 ULONG kernel_stack[4096];
53 ULONG double_trap_stack[4096];
54
55 /* These point to the aligned 3 pages */
56 ULONG init_stack;
57 ULONG init_stack_top;
58 ULONG trap_stack;
59 ULONG trap_stack_top;
60
61 /* Cached modules from the loader block */
62 PLOADER_MODULE CachedModules[MaximumCachedModuleType];
63
64 extern unsigned int _image_base__;
65 ULONG_PTR KERNEL_BASE = (ULONG_PTR)&_image_base__;
66
67 VOID INIT_FUNCTION _main(ULONG MultiBootMagic, PLOADER_PARAMETER_BLOCK _LoaderBlock);
68
69 #if defined (ALLOC_PRAGMA)
70 #pragma alloc_text(INIT, _main)
71 #endif
72
73 /* FUNCTIONS ****************************************************************/
74
75 /*
76 * @implemented
77 */
78 ULONG
79 STDCALL
80 KeGetRecommendedSharedDataAlignment(VOID)
81 {
82 return KeLargestCacheLine;
83 }
84
85 VOID
86 #ifdef __GNUC__
87 __attribute((noinline))
88 #endif
89 KiSystemStartup(BOOLEAN BootProcessor)
90 {
91 DPRINT("KiSystemStartup(%d)\n", BootProcessor);
92
93 /* Initialize the Application Processor */
94 if (!BootProcessor) KeApplicationProcessorInit();
95
96 /* Initialize the Processor with HAL */
97 HalInitializeProcessor(KeNumberProcessors, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
98
99 /* Load the Kernel if this is the Boot CPU, else inialize the App CPU only */
100 if (BootProcessor) {
101
102 /* Initialize the Kernel Executive */
103 ExpInitializeExecutive();
104
105 /* Free Initial Memory */
106 MiFreeInitMemory();
107
108 /* Never returns */
109 #if 0
110 /* FIXME:
111 * The initial thread isn't a real ETHREAD object, we cannot call PspExitThread.
112 */
113 PspExitThread(STATUS_SUCCESS);
114 #else
115 while (1) {
116 LARGE_INTEGER Timeout;
117 Timeout.QuadPart = 0x7fffffffffffffffLL;
118 KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
119 }
120 #endif
121 } else {
122
123 /* Do application processor initialization */
124 KeApplicationProcessorInitDispatcher();
125
126 /* Lower IRQL and go to Idle Thread */
127 KeLowerIrql(PASSIVE_LEVEL);
128 PsIdleThreadMain(NULL);
129 }
130
131 /* Bug Check and loop forever if anything failed */
132 KEBUGCHECK(0);
133 for(;;);
134 }
135
136 /*
137 * FUNCTION: Called by the boot loader to start the kernel
138 * ARGUMENTS:
139 * LoaderBlock = Pointer to boot parameters initialized by the boot
140 * loader
141 * NOTE: The boot parameters are stored in low memory which will become
142 * invalid after the memory managment is initialized so we make a local copy.
143 */
144 VOID
145 INIT_FUNCTION
146 _main(ULONG MultiBootMagic,
147 PLOADER_PARAMETER_BLOCK _LoaderBlock)
148 {
149 ULONG i;
150 ULONG size;
151 ULONG HalBase;
152 ULONG DriverBase;
153 ULONG DriverSize;
154 PIMAGE_NT_HEADERS NtHeader;
155 PIMAGE_OPTIONAL_HEADER OptHead;
156 CHAR* s;
157
158 /* Set up the Stacks (Initial Kernel Stack and Double Trap Stack)*/
159 trap_stack = PAGE_ROUND_UP(&double_trap_stack);
160 trap_stack_top = trap_stack + 3 * PAGE_SIZE;
161 init_stack = PAGE_ROUND_UP(&kernel_stack);
162 init_stack_top = init_stack + 3 * PAGE_SIZE;
163
164 /* Copy the Loader Block Data locally since Low-Memory will be wiped */
165 memcpy(&KeLoaderBlock, _LoaderBlock, sizeof(LOADER_PARAMETER_BLOCK));
166 memcpy(&KeLoaderModules[1],
167 (PVOID)KeLoaderBlock.ModsAddr,
168 sizeof(LOADER_MODULE) * KeLoaderBlock.ModsCount);
169 KeLoaderBlock.ModsCount++;
170 KeLoaderBlock.ModsAddr = (ULONG)&KeLoaderModules;
171
172 /* Save the Base Address */
173 MmSystemRangeStart = (PVOID)KeLoaderBlock.KernelBase;
174
175 /* Set the Command Line */
176 strcpy(KeLoaderCommandLine, (PCHAR)_LoaderBlock->CommandLine);
177 KeLoaderBlock.CommandLine = (ULONG)KeLoaderCommandLine;
178
179 /* Write the first Module (the Kernel) */
180 strcpy(KeLoaderModuleStrings[0], "ntoskrnl.exe");
181 KeLoaderModules[0].String = (ULONG)KeLoaderModuleStrings[0];
182 KeLoaderModules[0].ModStart = KERNEL_BASE;
183
184 /* Read PE Data */
185 NtHeader = RtlImageNtHeader((PVOID)KeLoaderModules[0].ModStart);
186 OptHead = &NtHeader->OptionalHeader;
187
188 /* Set Kernel Ending */
189 KeLoaderModules[0].ModEnd = KeLoaderModules[0].ModStart + PAGE_ROUND_UP((ULONG)OptHead->SizeOfImage);
190
191 /* Create a block for each module */
192 for (i = 1; i < KeLoaderBlock.ModsCount; i++) {
193
194 /* Check if we have to copy the path or not */
195 if ((s = strrchr((PCHAR)KeLoaderModules[i].String, '/')) != 0) {
196
197 strcpy(KeLoaderModuleStrings[i], s + 1);
198
199 } else {
200
201 strcpy(KeLoaderModuleStrings[i], (PCHAR)KeLoaderModules[i].String);
202 }
203
204 /* Substract the base Address in Physical Memory */
205 KeLoaderModules[i].ModStart -= 0x200000;
206
207 /* Add the Kernel Base Address in Virtual Memory */
208 KeLoaderModules[i].ModStart += KERNEL_BASE;
209
210 /* Substract the base Address in Physical Memory */
211 KeLoaderModules[i].ModEnd -= 0x200000;
212
213 /* Add the Kernel Base Address in Virtual Memory */
214 KeLoaderModules[i].ModEnd += KERNEL_BASE;
215
216 /* Select the proper String */
217 KeLoaderModules[i].String = (ULONG)KeLoaderModuleStrings[i];
218 }
219
220 /* Choose last module address as the final kernel address */
221 LastKernelAddress = PAGE_ROUND_UP(KeLoaderModules[KeLoaderBlock.ModsCount - 1].ModEnd);
222
223 /* Low level architecture specific initialization */
224 KeInit1((PCHAR)KeLoaderBlock.CommandLine, &LastKernelAddress);
225
226 /* Select the HAL Base */
227 HalBase = KeLoaderModules[1].ModStart;
228
229 /* Choose Driver Base */
230 DriverBase = LastKernelAddress;
231 LdrHalBase = (ULONG_PTR)DriverBase;
232
233 /* Initialize Module Management */
234 LdrInitModuleManagement();
235
236 /* Load HAL.DLL with the PE Loader */
237 LdrSafePEProcessModule((PVOID)HalBase,
238 (PVOID)DriverBase,
239 (PVOID)KERNEL_BASE,
240 &DriverSize);
241
242 /* Increase the last kernel address with the size of HAL */
243 LastKernelAddress += PAGE_ROUND_UP(DriverSize);
244
245 /* Load the Kernel with the PE Loader */
246 LdrSafePEProcessModule((PVOID)KERNEL_BASE,
247 (PVOID)KERNEL_BASE,
248 (PVOID)DriverBase,
249 &DriverSize);
250
251 /* Now select the final beginning and ending Kernel Addresses */
252 FirstKrnlPhysAddr = KeLoaderModules[0].ModStart - KERNEL_BASE + 0x200000;
253 LastKrnlPhysAddr = LastKernelAddress - KERNEL_BASE + 0x200000;
254
255 KeMemoryMapRangeCount = 0;
256 if (KeLoaderBlock.Flags & MB_FLAGS_MMAP_INFO) {
257
258 /* We have a memory map from the nice BIOS */
259 size = *((PULONG)(KeLoaderBlock.MmapAddr - sizeof(ULONG)));
260 i = 0;
261
262 /* Map it until we run out of size */
263 while (i < KeLoaderBlock.MmapLength) {
264
265 /* Copy into the Kernel Memory Map */
266 memcpy (&KeMemoryMap[KeMemoryMapRangeCount],
267 (PVOID)(KeLoaderBlock.MmapAddr + i),
268 sizeof(ADDRESS_RANGE));
269
270 /* Increase Memory Map Count */
271 KeMemoryMapRangeCount++;
272
273 /* Increase Size */
274 i += size;
275 }
276
277 /* Save data */
278 KeLoaderBlock.MmapLength = KeMemoryMapRangeCount * sizeof(ADDRESS_RANGE);
279 KeLoaderBlock.MmapAddr = (ULONG)KeMemoryMap;
280
281 } else {
282
283 /* Nothing from BIOS */
284 KeLoaderBlock.MmapLength = 0;
285 KeLoaderBlock.MmapAddr = (ULONG)KeMemoryMap;
286 }
287
288 /* Initialize the Debugger */
289 KdInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
290
291 /* Initialize HAL */
292 HalInitSystem (0, (PLOADER_PARAMETER_BLOCK)&KeLoaderBlock);
293
294 /* Display separator + ReactOS version at start of the debug log */
295 DPRINT1("---------------------------------------------------------------\n");
296 DPRINT1("ReactOS "KERNEL_VERSION_STR" (Build "KERNEL_VERSION_BUILD_STR")\n");
297
298 /* Do general System Startup */
299 KiSystemStartup(1);
300 }
301
302 /* EOF */