init.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805
  1. /*++
  2. Copyright (c) 2012 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. init.c
  9. Abstract:
  10. This module is responsible for initializing the Kernel Executive subsystem.
  11. Author:
  12. Evan Green 6-Aug-2012
  13. Environment:
  14. Kernel
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include <minoca/kernel/kernel.h>
  20. #include "keinit.h"
  21. #include <minoca/lib/bconf.h>
  22. #include "kep.h"
  23. //
  24. // ---------------------------------------------------------------- Definitions
  25. //
  26. //
  27. // ----------------------------------------------- Internal Function Prototypes
  28. //
  29. KSTATUS
  30. KepInitializeUserSharedData (
  31. PKERNEL_INITIALIZATION_BLOCK Parameters
  32. );
  33. KSTATUS
  34. KepInitializeCommandLine (
  35. PKERNEL_INITIALIZATION_BLOCK Parameters
  36. );
  37. KSTATUS
  38. KepInitializeEntropy (
  39. VOID
  40. );
  41. //
  42. // ------------------------------------------------------ Data Type Definitions
  43. //
  44. //
  45. // -------------------------------------------------------------------- Globals
  46. //
  47. //
  48. // Store the initial array of processor blocks, which is just an array of 1
  49. // pointing to P0's processor blocks.
  50. //
  51. PPROCESSOR_BLOCK KeP0ProcessorBlockArray = NULL;
  52. //
  53. // Structures that store the processor blocks and total number of processors.
  54. //
  55. PPROCESSOR_BLOCK *KeProcessorBlocks = &KeP0ProcessorBlockArray;
  56. ULONG KeProcessorBlockArraySize = 1;
  57. volatile ULONG KeProcessorCount = 1;
  58. volatile ULONG KeActiveProcessorCount = 0;
  59. //
  60. // Queued lock directory where all queued locks are stored. This is primarily
  61. // done to keep the root directory tidy.
  62. //
  63. extern POBJECT_HEADER KeQueuedLockDirectory;
  64. //
  65. // Directory for events with no parent, used primarily to keep the root
  66. // directory uncluttered.
  67. //
  68. extern POBJECT_HEADER KeEventDirectory;
  69. //
  70. // ------------------------------------------------------------------ Functions
  71. //
  72. KSTATUS
  73. KeInitialize (
  74. ULONG Phase,
  75. PKERNEL_INITIALIZATION_BLOCK Parameters
  76. )
  77. /*++
  78. Routine Description:
  79. This routine initializes the Kernel Executive subsystem. There is no
  80. synchronization in this routine, it is assumed that processors do not
  81. run through this routine concurrently.
  82. Arguments:
  83. Phase - Supplies the initialization phase. Valid values are 0 through 3.
  84. Parameters - Supplies a pointer to the kernel initialization block.
  85. Return Value:
  86. Status code.
  87. --*/
  88. {
  89. PPROCESSOR_BLOCK ProcessorBlock;
  90. KSTATUS Status;
  91. //
  92. // Initialize the processor block in phase 0. Phase 0 is called on all
  93. // processors.
  94. //
  95. if (Phase == 0) {
  96. ProcessorBlock = KeGetCurrentProcessorBlock();
  97. ProcessorBlock->RunLevel = RunLevelLow;
  98. KeInitializeSpinLock(&(ProcessorBlock->IpiListLock));
  99. INITIALIZE_LIST_HEAD(&(ProcessorBlock->IpiListHead));
  100. INITIALIZE_LIST_HEAD(&(ProcessorBlock->DpcList));
  101. KeInitializeSpinLock(&(ProcessorBlock->DpcLock));
  102. ProcessorBlock->CyclePeriodAccount = CycleAccountKernel;
  103. KepInitializeScheduler(ProcessorBlock);
  104. ASSERT(ProcessorBlock->ProcessorNumber < KeProcessorBlockArraySize);
  105. //
  106. // Add the current processor to the array of processor blocks.
  107. //
  108. KeProcessorBlocks[ProcessorBlock->ProcessorNumber] = ProcessorBlock;
  109. //
  110. // Initialize the system resource manager.
  111. //
  112. if (ProcessorBlock->ProcessorNumber == 0) {
  113. KeSystemFirmwareType = Parameters->FirmwareType;
  114. Status = KepInitializeSystemResources(Parameters, 0);
  115. if (!KSUCCESS(Status)) {
  116. goto InitializeEnd;
  117. }
  118. }
  119. //
  120. // Do architecture dependent initialization.
  121. //
  122. Status = KepArchInitialize(Parameters, Phase);
  123. if (!KSUCCESS(Status)) {
  124. goto InitializeEnd;
  125. }
  126. RtlAtomicAdd32(&KeActiveProcessorCount, 1);
  127. //
  128. // Fire up the built in base video library.
  129. //
  130. Status = KepInitializeBaseVideo(Parameters);
  131. if (!KSUCCESS(Status)) {
  132. goto InitializeEnd;
  133. }
  134. //
  135. // Set up directories for events and queued locks in phase 1.
  136. //
  137. } else if (Phase == 1) {
  138. ProcessorBlock = KeGetCurrentProcessorBlock();
  139. if (ProcessorBlock->ProcessorNumber == 0) {
  140. Status = ArFinishBootProcessorInitialization();
  141. if (!KSUCCESS(Status)) {
  142. goto InitializeEnd;
  143. }
  144. Status = KepInitializeCommandLine(Parameters);
  145. if (!KSUCCESS(Status)) {
  146. goto InitializeEnd;
  147. }
  148. Status = KepInitializeSystemResources(NULL, 1);
  149. if (!KSUCCESS(Status)) {
  150. goto InitializeEnd;
  151. }
  152. KeQueuedLockDirectory = ObCreateObject(
  153. ObjectDirectory,
  154. NULL,
  155. "QueuedLocks",
  156. sizeof("QueuedLocks"),
  157. sizeof(OBJECT_HEADER),
  158. NULL,
  159. OBJECT_FLAG_USE_NAME_DIRECTLY,
  160. KE_ALLOCATION_TAG);
  161. if (KeQueuedLockDirectory == NULL) {
  162. Status = STATUS_INSUFFICIENT_RESOURCES;
  163. goto InitializeEnd;
  164. }
  165. KeEventDirectory = ObCreateObject(ObjectDirectory,
  166. NULL,
  167. "Events",
  168. sizeof("Events"),
  169. sizeof(OBJECT_HEADER),
  170. NULL,
  171. OBJECT_FLAG_USE_NAME_DIRECTLY,
  172. KE_ALLOCATION_TAG);
  173. if (KeEventDirectory == NULL) {
  174. Status = STATUS_INSUFFICIENT_RESOURCES;
  175. goto InitializeEnd;
  176. }
  177. //
  178. // Initialize system crash support.
  179. //
  180. Status = KepInitializeCrashDumpSupport();
  181. if (!KSUCCESS(Status)) {
  182. goto InitializeEnd;
  183. }
  184. }
  185. //
  186. // Initialize the clock information, run on all processors.
  187. //
  188. KepInitializeClock(ProcessorBlock);
  189. //
  190. // Create the timer queue for the processor.
  191. //
  192. ProcessorBlock->TimerData = KepCreateTimerData();
  193. if (ProcessorBlock->TimerData == NULL) {
  194. Status = STATUS_INSUFFICIENT_RESOURCES;
  195. goto InitializeEnd;
  196. }
  197. //
  198. // Perform architecture-specific setup for the user shared data page.
  199. //
  200. ArSetUpUserSharedDataFeatures();
  201. Status = STATUS_SUCCESS;
  202. //
  203. // Create the worker threads in phase 2.
  204. //
  205. } else if (Phase == 2) {
  206. ProcessorBlock = KeGetCurrentProcessorBlock();
  207. //
  208. // Call the initialize clock routine again (only on processor 0) now
  209. // that the true time counter has been established.
  210. //
  211. KepInitializeClock(ProcessorBlock);
  212. Status = KepInitializeSystemWorkQueue();
  213. if (!KSUCCESS(Status)) {
  214. goto InitializeEnd;
  215. }
  216. Status= KepInitializeUserSharedData(Parameters);
  217. if (!KSUCCESS(Status)) {
  218. goto InitializeEnd;
  219. }
  220. //
  221. // Phase 3 occurs after I/O has started up.
  222. //
  223. } else {
  224. ASSERT(Phase == 3);
  225. Status = KepInitializeEntropy();
  226. if (!KSUCCESS(Status)) {
  227. goto InitializeEnd;
  228. }
  229. }
  230. InitializeEnd:
  231. return Status;
  232. }
  233. PPROCESSOR_START_BLOCK
  234. KePrepareForProcessorLaunch (
  235. VOID
  236. )
  237. /*++
  238. Routine Description:
  239. This routine prepares the kernel's internal structures for a new processor
  240. coming online.
  241. Arguments:
  242. None.
  243. Return Value:
  244. Returns a pointer to an allocated and filled out processor start block
  245. structure. At this point the kernel will be ready for this processor to
  246. come online at any time.
  247. NULL on failure.
  248. --*/
  249. {
  250. ULONG ArraySizeInBytes;
  251. PPROCESSOR_BLOCK *NewProcessorBlockArray;
  252. ULONG NewProcessorBlockArraySize;
  253. PPROCESSOR_BLOCK *OldArray;
  254. ULONG ProcessorNumber;
  255. PPROCESSOR_START_BLOCK StartBlock;
  256. KSTATUS Status;
  257. StartBlock = NULL;
  258. //
  259. // Get the next processor number.
  260. //
  261. ProcessorNumber = RtlAtomicAdd32(&KeProcessorCount, 1);
  262. //
  263. // If needed, expand the the processor block pointer array to accomodate
  264. // this new processor.
  265. //
  266. if (ProcessorNumber >= KeProcessorBlockArraySize) {
  267. NewProcessorBlockArraySize = KeProcessorBlockArraySize * 2;
  268. ASSERT(NewProcessorBlockArraySize > ProcessorNumber);
  269. ArraySizeInBytes = NewProcessorBlockArraySize *
  270. sizeof(PPROCESSOR_BLOCK);
  271. NewProcessorBlockArray = MmAllocateNonPagedPool(ArraySizeInBytes,
  272. KE_ALLOCATION_TAG);
  273. if (NewProcessorBlockArray == NULL) {
  274. Status = STATUS_INSUFFICIENT_RESOURCES;
  275. goto PrepareForProcessorLaunchEnd;
  276. }
  277. OldArray = KeProcessorBlocks;
  278. RtlCopyMemory(NewProcessorBlockArray,
  279. OldArray,
  280. KeProcessorBlockArraySize * sizeof(PVOID));
  281. //
  282. // Assign the new array, assign the new array size, then free the old
  283. // array.
  284. //
  285. KeProcessorBlocks = NewProcessorBlockArray;
  286. KeProcessorBlockArraySize = NewProcessorBlockArraySize;
  287. if (OldArray != &KeP0ProcessorBlockArray) {
  288. MmFreeNonPagedPool(OldArray);
  289. }
  290. }
  291. //
  292. // Allocate the start block structure.
  293. //
  294. StartBlock = MmAllocateNonPagedPool(sizeof(PROCESSOR_START_BLOCK),
  295. KE_ALLOCATION_TAG);
  296. if (StartBlock == NULL) {
  297. Status = STATUS_INSUFFICIENT_RESOURCES;
  298. goto PrepareForProcessorLaunchEnd;
  299. }
  300. RtlZeroMemory(StartBlock, sizeof(PROCESSOR_START_BLOCK));
  301. //
  302. // Allocate basic processor structures.
  303. //
  304. StartBlock->ProcessorNumber = ProcessorNumber;
  305. StartBlock->ProcessorStructures =
  306. ArAllocateProcessorStructures(ProcessorNumber);
  307. if (StartBlock->ProcessorStructures == NULL) {
  308. Status = STATUS_INSUFFICIENT_RESOURCES;
  309. goto PrepareForProcessorLaunchEnd;
  310. }
  311. //
  312. // MM has some structures to create as well.
  313. //
  314. Status = MmPrepareForProcessorLaunch(StartBlock);
  315. if (!KSUCCESS(Status)) {
  316. goto PrepareForProcessorLaunchEnd;
  317. }
  318. Status = STATUS_SUCCESS;
  319. PrepareForProcessorLaunchEnd:
  320. if (!KSUCCESS(Status)) {
  321. if (StartBlock != NULL) {
  322. MmDestroyProcessorStartBlock(StartBlock);
  323. if (StartBlock->ProcessorStructures != NULL) {
  324. ArFreeProcessorStructures(StartBlock->ProcessorStructures);
  325. }
  326. MmFreeNonPagedPool(StartBlock);
  327. StartBlock = NULL;
  328. }
  329. }
  330. return StartBlock;
  331. }
  332. VOID
  333. KeFreeProcessorStartBlock (
  334. PPROCESSOR_START_BLOCK StartBlock,
  335. BOOL FreeResourcesInside
  336. )
  337. /*++
  338. Routine Description:
  339. This routine frees a processor start block structure.
  340. Arguments:
  341. StartBlock - Supplies a pointer to the start block structure to free.
  342. FreeResourcesInside - Supplies a boolean indicating whether or not to free
  343. the resources contained inside the start block.
  344. Return Value:
  345. None.
  346. --*/
  347. {
  348. if (FreeResourcesInside != FALSE) {
  349. MmDestroyProcessorStartBlock(StartBlock);
  350. if (StartBlock->ProcessorStructures != NULL) {
  351. ArFreeProcessorStructures(StartBlock->ProcessorStructures);
  352. }
  353. }
  354. MmFreeNonPagedPool(StartBlock);
  355. return;
  356. }
  357. //
  358. // --------------------------------------------------------- Internal Functions
  359. //
  360. KSTATUS
  361. KepInitializeUserSharedData (
  362. PKERNEL_INITIALIZATION_BLOCK Parameters
  363. )
  364. /*++
  365. Routine Description:
  366. This routine initializes the shared user data area.
  367. Arguments:
  368. Parameters - Supplies a pointer to the kernel initialization block.
  369. Return Value:
  370. Status code.
  371. --*/
  372. {
  373. CALENDAR_TIME CalendarTime;
  374. KSTATUS Status;
  375. SYSTEM_TIME SystemTime;
  376. PUSER_SHARED_DATA UserSharedData;
  377. UserSharedData = MmGetUserSharedData();
  378. UserSharedData->EncodedSystemVersion = KeEncodedVersion;
  379. UserSharedData->SystemVersionSerial = KeVersionSerial;
  380. UserSharedData->BuildTime = KeBuildTime;
  381. UserSharedData->TimeCounterFrequency = HlQueryTimeCounterFrequency();
  382. UserSharedData->ProcessorCounterFrequency =
  383. HlQueryProcessorCounterFrequency();
  384. //
  385. // If no calendar services are around, set this to the boot time and go
  386. // from there.
  387. //
  388. if (UserSharedData->TimeOffset.Seconds == 0) {
  389. Status = KepSetTimeOffset(&(Parameters->BootTime), NULL);
  390. if (!KSUCCESS(Status)) {
  391. goto InitializeUserSharedDataEnd;
  392. }
  393. }
  394. //
  395. // Print the boot time out to the debugger.
  396. //
  397. KeGetSystemTime(&SystemTime);
  398. RtlSystemTimeToGmtCalendarTime(&(Parameters->BootTime), &CalendarTime);
  399. RtlDebugPrint("Boot time: %02d/%02d/%04d %02d:%02d:%02d GMT\n",
  400. CalendarTime.Month + 1,
  401. CalendarTime.Day,
  402. CalendarTime.Year,
  403. CalendarTime.Hour,
  404. CalendarTime.Minute,
  405. CalendarTime.Second);
  406. Status = STATUS_SUCCESS;
  407. InitializeUserSharedDataEnd:
  408. return Status;
  409. }
  410. KSTATUS
  411. KepInitializeCommandLine (
  412. PKERNEL_INITIALIZATION_BLOCK Parameters
  413. )
  414. /*++
  415. Routine Description:
  416. This routine initializes and parses the kernel command line parameters.
  417. Arguments:
  418. Parameters - Supplies a pointer to the kernel initialization block.
  419. Return Value:
  420. Status code.
  421. --*/
  422. {
  423. UINTN AllocationSize;
  424. PKERNEL_ARGUMENT Argument;
  425. UINTN ArgumentCount;
  426. PBOOT_ENTRY BootEntry;
  427. CHAR Character;
  428. PSTR Component;
  429. PSTR Current;
  430. PKERNEL_COMMAND_LINE Information;
  431. BOOL InQuote;
  432. PSTR Line;
  433. PSTR LineCopy;
  434. PSTR Name;
  435. PCSTR OriginalString;
  436. ULONG Pass;
  437. UINTN StringSize;
  438. ULONG ValueIndex;
  439. BootEntry = Parameters->BootEntry;
  440. if (BootEntry == NULL) {
  441. return STATUS_SUCCESS;
  442. }
  443. OriginalString = BootEntry->KernelArguments;
  444. StringSize = RtlStringLength(OriginalString) + 1;
  445. if (StringSize > KERNEL_MAX_COMMAND_LINE) {
  446. StringSize = KERNEL_MAX_COMMAND_LINE;
  447. RtlDebugPrint("Truncated kernel command line.\n");
  448. }
  449. Line = MmAllocateNonPagedPool(StringSize, KE_ALLOCATION_TAG);
  450. if (Line == NULL) {
  451. return STATUS_INSUFFICIENT_RESOURCES;
  452. }
  453. if (StringSize != 1) {
  454. RtlCopyMemory(Line, OriginalString, StringSize);
  455. }
  456. Line[StringSize - 1] = '\0';
  457. Current = Line;
  458. Argument = NULL;
  459. ArgumentCount = 0;
  460. Information = NULL;
  461. //
  462. // Parse the arguments in the form component.name=value1,value2,...
  463. //
  464. for (Pass = 0; Pass < 2; Pass += 1) {
  465. while (*Current != '\0') {
  466. Component = NULL;
  467. Name = NULL;
  468. //
  469. // Skip leading spaces.
  470. //
  471. while (RtlIsCharacterBlank(*Current) != FALSE) {
  472. Current += 1;
  473. }
  474. if (*Current == '\0') {
  475. break;
  476. }
  477. Component = Current;
  478. while ((*Current != '\0') &&
  479. (*Current != '.') &&
  480. (RtlIsCharacterSpace(*Current) == FALSE)) {
  481. Current += 1;
  482. }
  483. if (*Current != '.') {
  484. if (Argument != NULL) {
  485. RtlDebugPrint("Ignoring argument starting at: %s\n",
  486. Component);
  487. }
  488. continue;
  489. }
  490. if (Argument != NULL) {
  491. *Current = '\0';
  492. }
  493. Current += 1;
  494. Name = Current;
  495. while ((*Current != '\0') &&
  496. (*Current != '=') &&
  497. (RtlIsCharacterBlank(*Current) == FALSE)) {
  498. Current += 1;
  499. }
  500. if (Argument != NULL) {
  501. Argument->Component = Component;
  502. Argument->Name = Name;
  503. }
  504. //
  505. // If the argument contains no equals, it's just a component and
  506. // name.
  507. //
  508. Character = *Current;
  509. if (Argument != NULL) {
  510. *Current = '\0';
  511. }
  512. Current += 1;
  513. if (Character != '=') {
  514. if (Information != NULL) {
  515. Information->ArgumentCount += 1;
  516. }
  517. continue;
  518. }
  519. for (ValueIndex = 0;
  520. ValueIndex < KERNEL_MAX_ARGUMENT_VALUES;
  521. ValueIndex += 1) {
  522. if (Argument != NULL) {
  523. Argument->Values[ValueIndex] = Current;
  524. }
  525. InQuote = FALSE;
  526. while (*Current != '\0') {
  527. if (*Current == '"') {
  528. InQuote = !InQuote;
  529. } else if (InQuote == FALSE) {
  530. if ((*Current == ',') ||
  531. (RtlIsCharacterBlank(*Current) != FALSE)) {
  532. break;
  533. }
  534. }
  535. Current += 1;
  536. }
  537. if (*Current != ',') {
  538. ValueIndex += 1;
  539. break;
  540. }
  541. if (ValueIndex == KERNEL_MAX_ARGUMENT_VALUES - 1) {
  542. if (Argument != NULL) {
  543. RtlDebugPrint("Combining argument values starting at "
  544. "%s\n",
  545. Current);
  546. }
  547. } else {
  548. if (Argument != NULL) {
  549. *Current = '\0';
  550. }
  551. Current += 1;
  552. }
  553. }
  554. if (Argument != NULL) {
  555. Argument->ValueCount = ValueIndex;
  556. }
  557. //
  558. // Get past any remaining non-blanks.
  559. //
  560. while ((*Current != '\0') &&
  561. (RtlIsCharacterBlank(*Current) == FALSE)) {
  562. Current += 1;
  563. }
  564. if (Argument != NULL) {
  565. *Current = '\0';
  566. Argument += 1;
  567. }
  568. ArgumentCount += 1;
  569. }
  570. if (Pass != 0) {
  571. break;
  572. }
  573. //
  574. // Allocate the complete structure, which includes the main structure,
  575. // element for each argument, and a complete copy of the string which
  576. // will be chopped up.
  577. //
  578. AllocationSize = sizeof(KERNEL_COMMAND_LINE) +
  579. (ArgumentCount * sizeof(KERNEL_ARGUMENT)) +
  580. StringSize;
  581. Information = MmAllocateNonPagedPool(AllocationSize, KE_ALLOCATION_TAG);
  582. if (Information == NULL) {
  583. MmFreeNonPagedPool(Line);
  584. return STATUS_INSUFFICIENT_RESOURCES;
  585. }
  586. RtlZeroMemory(Information, AllocationSize);
  587. Information->Line = Line;
  588. Information->LineSize = StringSize;
  589. Information->Arguments = (PKERNEL_ARGUMENT)(Information + 1);
  590. Information->ArgumentCount = ArgumentCount;
  591. LineCopy = (PSTR)(Information->Arguments + ArgumentCount);
  592. RtlCopyMemory(LineCopy, Line, StringSize);
  593. Argument = &(Information->Arguments[0]);
  594. Current = LineCopy;
  595. ArgumentCount = 0;
  596. }
  597. ASSERT(ArgumentCount == Information->ArgumentCount);
  598. KeCommandLine = Information;
  599. return STATUS_SUCCESS;
  600. }