1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: ntoskrnl/ke/arm/kiinit.c 5 * PURPOSE: Implements the kernel entry point for ARM machines 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 VOID 16 NTAPI 17 KdPortPutByteEx( 18 PCPPORT PortInformation, 19 UCHAR ByteToSend 20 ); 21 22 /* GLOBALS ********************************************************************/ 23 24 KINTERRUPT KxUnexpectedInterrupt; 25 BOOLEAN KeIsArmV6; 26 ULONG KeNumberProcessIds; 27 ULONG KeNumberTbEntries; 28 ULONG ProcessCount; // PERF 29 extern PVOID KiArmVectorTable; 30 #define __ARMV6__ KeIsArmV6 31 32 /* FUNCTIONS ******************************************************************/ 33 34 VOID 35 NTAPI 36 KiInitMachineDependent(VOID) 37 { 38 /* There is nothing to do on ARM */ 39 return; 40 } 41 42 VOID 43 NTAPI 44 KiInitializeKernel(IN PKPROCESS InitProcess, 45 IN PKTHREAD InitThread, 46 IN PVOID IdleStack, 47 IN PKPRCB Prcb, 48 IN CCHAR Number, 49 IN PLOADER_PARAMETER_BLOCK LoaderBlock) 50 { 51 PKIPCR Pcr = (PKIPCR)KeGetPcr(); 52 ULONG PageDirectory[2]; 53 ULONG i; 54 55 /* Set the default NX policy (opt-in) */ 56 SharedUserData->NXSupportPolicy = NX_SUPPORT_POLICY_OPTIN; 57 58 /* Initialize spinlocks and DPC data */ 59 KiInitSpinLocks(Prcb, Number); 60 61 /* Set stack pointers */ 62 //Pcr->InitialStack = IdleStack; 63 Pcr->Prcb.SpBase = IdleStack; // ??? 64 65 /* Check if this is the Boot CPU */ 66 if (!Number) 67 { 68 /* Setup the unexpected interrupt */ 69 KxUnexpectedInterrupt.DispatchAddress = KiUnexpectedInterrupt; 70 for (i = 0; i < 4; i++) 71 { 72 /* Copy the template code */ 73 KxUnexpectedInterrupt.DispatchCode[i] = ((PULONG)KiInterruptTemplate)[i]; 74 } 75 76 /* Set DMA coherency */ 77 KiDmaIoCoherency = 0; 78 79 /* Sweep D-Cache */ 80 HalSweepDcache(); 81 82 /* Set boot-level flags */ 83 KeProcessorArchitecture = PROCESSOR_ARCHITECTURE_ARM; 84 KeFeatureBits = 0; 85 /// FIXME: just a wild guess 86 KeProcessorLevel = (USHORT)(Pcr->Prcb.ProcessorState.ArchState.Cp15_Cr0_CpuId >> 8); 87 KeProcessorRevision = (USHORT)(Pcr->Prcb.ProcessorState.ArchState.Cp15_Cr0_CpuId & 0xFF); 88 #if 0 89 /* Set the current MP Master KPRCB to the Boot PRCB */ 90 Prcb->MultiThreadSetMaster = Prcb; 91 #endif 92 /* Lower to APC_LEVEL */ 93 KeLowerIrql(APC_LEVEL); 94 95 /* Initialize portable parts of the OS */ 96 KiInitSystem(); 97 98 /* Initialize the Idle Process and the Process Listhead */ 99 InitializeListHead(&KiProcessListHead); 100 PageDirectory[0] = 0; 101 PageDirectory[1] = 0; 102 KeInitializeProcess(InitProcess, 103 0, 104 MAXULONG_PTR, 105 PageDirectory, 106 FALSE); 107 InitProcess->QuantumReset = MAXCHAR; 108 } 109 else 110 { 111 /* FIXME-V6: See if we want to support MP */ 112 DPRINT1("ARM MPCore not supported\n"); 113 } 114 115 /* Setup the Idle Thread */ 116 KeInitializeThread(InitProcess, 117 InitThread, 118 NULL, 119 NULL, 120 NULL, 121 NULL, 122 NULL, 123 IdleStack); 124 InitThread->NextProcessor = Number; 125 InitThread->Priority = HIGH_PRIORITY; 126 InitThread->State = Running; 127 InitThread->Affinity = 1 << Number; 128 InitThread->WaitIrql = DISPATCH_LEVEL; 129 InitProcess->ActiveProcessors = 1 << Number; 130 131 /* HACK for MmUpdatePageDir */ 132 ((PETHREAD)InitThread)->ThreadsProcess = (PEPROCESS)InitProcess; 133 134 /* Set up the thread-related fields in the PRCB */ 135 Prcb->CurrentThread = InitThread; 136 Prcb->NextThread = NULL; 137 Prcb->IdleThread = InitThread; 138 139 /* Initialize the Kernel Executive */ 140 ExpInitializeExecutive(Number, LoaderBlock); 141 142 /* Only do this on the boot CPU */ 143 if (!Number) 144 { 145 /* Calculate the time reciprocal */ 146 KiTimeIncrementReciprocal = 147 KiComputeReciprocal(KeMaximumIncrement, 148 &KiTimeIncrementShiftCount); 149 150 /* Update DPC Values in case they got updated by the executive */ 151 Prcb->MaximumDpcQueueDepth = KiMaximumDpcQueueDepth; 152 Prcb->MinimumDpcRate = KiMinimumDpcRate; 153 Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold; 154 } 155 156 /* Raise to Dispatch */ 157 KfRaiseIrql(DISPATCH_LEVEL); 158 159 /* Set the Idle Priority to 0. This will jump into Phase 1 */ 160 KeSetPriorityThread(InitThread, 0); 161 162 /* If there's no thread scheduled, put this CPU in the Idle summary */ 163 KiAcquirePrcbLock(Prcb); 164 if (!Prcb->NextThread) KiIdleSummary |= 1 << Number; 165 KiReleasePrcbLock(Prcb); 166 167 /* Raise back to HIGH_LEVEL and clear the PRCB for the loader block */ 168 KfRaiseIrql(HIGH_LEVEL); 169 LoaderBlock->Prcb = 0; 170 } 171 172 //C_ASSERT((PKIPCR)KeGetPcr() == (PKIPCR)0xFFDFF000); 173 //C_ASSERT((FIELD_OFFSET(KIPCR, FirstLevelDcacheSize) & 4) == 0); 174 //C_ASSERT(sizeof(KIPCR) <= PAGE_SIZE); 175 176 VOID 177 NTAPI 178 KiInitializePcr(IN ULONG ProcessorNumber, 179 IN PKIPCR Pcr, 180 IN PKTHREAD IdleThread, 181 IN PVOID PanicStack, 182 IN PVOID InterruptStack) 183 { 184 ULONG i; 185 186 /* Set the Current Thread */ 187 Pcr->Prcb.CurrentThread = IdleThread; 188 189 /* Set pointers to ourselves */ 190 Pcr->Self = (PKPCR)Pcr; 191 Pcr->CurrentPrcb = &Pcr->Prcb; 192 193 /* Set the PCR Version */ 194 Pcr->MajorVersion = PCR_MAJOR_VERSION; 195 Pcr->MinorVersion = PCR_MINOR_VERSION; 196 197 /* Set the PCRB Version */ 198 Pcr->Prcb.MajorVersion = PRCB_MAJOR_VERSION; 199 Pcr->Prcb.MinorVersion = PRCB_MINOR_VERSION; 200 201 /* Set the Build Type */ 202 Pcr->Prcb.BuildType = 0; 203 #ifndef CONFIG_SMP 204 Pcr->Prcb.BuildType |= PRCB_BUILD_UNIPROCESSOR; 205 #endif 206 #if DBG 207 Pcr->Prcb.BuildType |= PRCB_BUILD_DEBUG; 208 #endif 209 210 /* Set the Processor Number and current Processor Mask */ 211 Pcr->Prcb.Number = (UCHAR)ProcessorNumber; 212 Pcr->Prcb.SetMember = 1 << ProcessorNumber; 213 214 /* Set the PRCB for this Processor */ 215 KiProcessorBlock[ProcessorNumber] = Pcr->CurrentPrcb; 216 217 /* Start us out at PASSIVE_LEVEL */ 218 Pcr->CurrentIrql = PASSIVE_LEVEL; 219 220 /* Set the stacks */ 221 Pcr->Prcb.PanicStackBase = (ULONG)PanicStack; 222 Pcr->Prcb.IsrStack = InterruptStack; 223 #if 0 224 /* Setup the processor set */ 225 Pcr->Prcb.MultiThreadProcessorSet = Pcr->Prcb.SetMember; 226 #endif 227 228 /* Copy cache information from the loader block */ 229 Pcr->Prcb.Cache[FirstLevelDcache].Type = CacheData; 230 Pcr->Prcb.Cache[FirstLevelDcache].Level = 1; 231 Pcr->Prcb.Cache[FirstLevelDcache].Associativity = 0; // FIXME 232 Pcr->Prcb.Cache[FirstLevelDcache].LineSize = KeLoaderBlock->u.Arm.FirstLevelDcacheFillSize; 233 Pcr->Prcb.Cache[FirstLevelDcache].Size = KeLoaderBlock->u.Arm.FirstLevelDcacheSize; 234 235 Pcr->Prcb.Cache[SecondLevelDcache].Type = CacheData; 236 Pcr->Prcb.Cache[SecondLevelDcache].Level = 2; 237 Pcr->Prcb.Cache[SecondLevelDcache].Associativity = 0; // FIXME 238 Pcr->Prcb.Cache[SecondLevelDcache].LineSize = KeLoaderBlock->u.Arm.SecondLevelDcacheFillSize; 239 Pcr->Prcb.Cache[SecondLevelDcache].Size = KeLoaderBlock->u.Arm.SecondLevelDcacheSize; 240 241 Pcr->Prcb.Cache[FirstLevelIcache].Type = CacheInstruction; 242 Pcr->Prcb.Cache[FirstLevelIcache].Level = 1; 243 Pcr->Prcb.Cache[FirstLevelIcache].Associativity = 0; // FIXME 244 Pcr->Prcb.Cache[FirstLevelIcache].LineSize = KeLoaderBlock->u.Arm.FirstLevelIcacheFillSize; 245 Pcr->Prcb.Cache[FirstLevelIcache].Size = KeLoaderBlock->u.Arm.FirstLevelIcacheSize; 246 247 Pcr->Prcb.Cache[SecondLevelIcache].Type = CacheInstruction; 248 Pcr->Prcb.Cache[SecondLevelIcache].Level = 2; 249 Pcr->Prcb.Cache[SecondLevelIcache].Associativity = 0; // FIXME 250 Pcr->Prcb.Cache[SecondLevelIcache].LineSize = KeLoaderBlock->u.Arm.SecondLevelIcacheFillSize; 251 Pcr->Prcb.Cache[SecondLevelIcache].Size = KeLoaderBlock->u.Arm.SecondLevelIcacheSize; 252 253 /* Set global d-cache fill and alignment values */ 254 if (Pcr->Prcb.Cache[SecondLevelDcache].Size == 0) 255 { 256 /* Use the first level */ 257 Pcr->Prcb.Cache[GlobalDcache] = Pcr->Prcb.Cache[FirstLevelDcache]; 258 } 259 else 260 { 261 /* Use the second level */ 262 Pcr->Prcb.Cache[GlobalDcache] = Pcr->Prcb.Cache[SecondLevelDcache]; 263 } 264 265 /* Set the alignment */ 266 //Pcr->DcacheAlignment = Pcr->DcacheFillSize - 1; 267 268 /* Set global i-cache fill and alignment values */ 269 if (Pcr->Prcb.Cache[SecondLevelIcache].Size == 0) 270 { 271 /* Use the first level */ 272 Pcr->Prcb.Cache[GlobalIcache] = Pcr->Prcb.Cache[FirstLevelIcache]; 273 } 274 else 275 { 276 /* Use the second level */ 277 Pcr->Prcb.Cache[GlobalIcache] = Pcr->Prcb.Cache[SecondLevelIcache]; 278 } 279 280 /* Set the alignment */ 281 //Pcr->IcacheAlignment = Pcr->IcacheFillSize - 1; 282 283 /* Set processor information */ 284 //Pcr->ProcessorId = KeArmIdCodeRegisterGet().AsUlong; 285 286 /* Set all interrupt routines to unexpected interrupts as well */ 287 for (i = 0; i < MAXIMUM_VECTOR; i++) 288 { 289 /* Point to the same template */ 290 Pcr->Idt[i] = (PVOID)&KxUnexpectedInterrupt.DispatchCode; 291 } 292 293 /* Set default stall factor */ 294 Pcr->StallScaleFactor = 50; 295 296 /* Setup software interrupts */ 297 Pcr->Idt[PASSIVE_LEVEL] = KiPassiveRelease; 298 Pcr->Idt[APC_LEVEL] = KiApcInterrupt; 299 Pcr->Idt[DISPATCH_LEVEL] = KiDispatchInterrupt; 300 #if 0 301 Pcr->ReservedVectors = (1 << PASSIVE_LEVEL) | 302 (1 << APC_LEVEL) | 303 (1 << DISPATCH_LEVEL) | 304 (1 << IPI_LEVEL); 305 #endif 306 } 307 308 VOID 309 KiInitializeMachineType(VOID) 310 { 311 /* Detect ARM version */ 312 KeIsArmV6 = KeArmIdCodeRegisterGet().Architecture >= 7; 313 314 /* Set the number of TLB entries and ASIDs */ 315 KeNumberTbEntries = 64; 316 if (__ARMV6__) 317 { 318 /* 256 ASIDs on v6/v7 */ 319 KeNumberProcessIds = 256; 320 } 321 else 322 { 323 /* The TLB is VIVT on v4/v5 */ 324 KeNumberProcessIds = 0; 325 } 326 } 327 328 DECLSPEC_NORETURN 329 VOID 330 KiInitializeSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock) 331 { 332 ULONG Cpu; 333 PKTHREAD InitialThread; 334 PKPROCESS InitialProcess; 335 ARM_CONTROL_REGISTER ControlRegister; 336 PKIPCR Pcr = (PKIPCR)KeGetPcr(); 337 PKTHREAD Thread; 338 339 /* Flush the TLB */ 340 KeFlushTb(); 341 342 /* Save the loader block and get the current CPU */ 343 KeLoaderBlock = LoaderBlock; 344 Cpu = KeNumberProcessors; 345 346 /* Save the initial thread and process */ 347 InitialThread = (PKTHREAD)LoaderBlock->Thread; 348 InitialProcess = (PKPROCESS)LoaderBlock->Process; 349 350 /* Clean the APC List Head */ 351 InitializeListHead(&InitialThread->ApcState.ApcListHead[KernelMode]); 352 353 /* Initialize the machine type */ 354 KiInitializeMachineType(); 355 356 /* Skip initial setup if this isn't the Boot CPU */ 357 if (Cpu) goto AppCpuInit; 358 359 /* Initialize the PCR */ 360 RtlZeroMemory(Pcr, PAGE_SIZE); 361 KiInitializePcr(Cpu, 362 Pcr, 363 InitialThread, 364 (PVOID)LoaderBlock->u.Arm.PanicStack, 365 (PVOID)LoaderBlock->u.Arm.InterruptStack); 366 367 /* Now sweep caches */ 368 HalSweepIcache(); 369 HalSweepDcache(); 370 371 /* Set us as the current process */ 372 InitialThread->ApcState.Process = InitialProcess; 373 374 AppCpuInit: 375 /* Setup CPU-related fields */ 376 Pcr->Prcb.Number = Cpu; 377 Pcr->Prcb.SetMember = 1 << Cpu; 378 379 /* Initialize the Processor with HAL */ 380 HalInitializeProcessor(Cpu, KeLoaderBlock); 381 382 /* Set active processors */ 383 KeActiveProcessors |= Pcr->Prcb.SetMember; 384 KeNumberProcessors++; 385 386 /* Check if this is the boot CPU */ 387 if (!Cpu) 388 { 389 /* Initialize debugging system */ 390 KdInitSystem(0, KeLoaderBlock); 391 392 /* Check for break-in */ 393 if (KdPollBreakIn()) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C); 394 } 395 396 /* Raise to HIGH_LEVEL */ 397 KfRaiseIrql(HIGH_LEVEL); 398 399 /* Set the exception address to high */ 400 ControlRegister = KeArmControlRegisterGet(); 401 ControlRegister.HighVectors = TRUE; 402 KeArmControlRegisterSet(ControlRegister); 403 404 /* Setup the exception vector table */ 405 RtlCopyMemory((PVOID)0xFFFF0000, &KiArmVectorTable, 14 * sizeof(PVOID)); 406 407 /* Initialize the rest of the kernel now */ 408 KiInitializeKernel((PKPROCESS)LoaderBlock->Process, 409 (PKTHREAD)LoaderBlock->Thread, 410 (PVOID)LoaderBlock->KernelStack, 411 &Pcr->Prcb, 412 Pcr->Prcb.Number, 413 KeLoaderBlock); 414 415 /* Set the priority of this thread to 0 */ 416 Thread = KeGetCurrentThread(); 417 Thread->Priority = 0; 418 419 /* Force interrupts enabled and lower IRQL back to DISPATCH_LEVEL */ 420 _enable(); 421 KfLowerIrql(DISPATCH_LEVEL); 422 423 /* Set the right wait IRQL */ 424 Thread->WaitIrql = DISPATCH_LEVEL; 425 426 /* Jump into the idle loop */ 427 KiIdleLoop(); 428 } 429 430 ULONG 431 DbgPrintEarly(const char *fmt, ...) 432 { 433 va_list args; 434 unsigned int i; 435 char Buffer[1024]; 436 PCHAR String = Buffer; 437 438 va_start(args, fmt); 439 i = vsprintf(Buffer, fmt, args); 440 va_end(args); 441 442 /* Output the message */ 443 while (*String != 0) 444 { 445 if (*String == '\n') 446 { 447 KdPortPutByteEx(NULL, '\r'); 448 } 449 KdPortPutByteEx(NULL, *String); 450 String++; 451 } 452 453 return STATUS_SUCCESS; 454 } 455