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