init.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  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 initializes the process and thread 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 <minoca/lib/bconf.h>
  21. #include <minoca/kernel/bootload.h>
  22. #include "psp.h"
  23. //
  24. // ---------------------------------------------------------------- Definitions
  25. //
  26. #define IDLE_THREAD_NAME_LENGTH 10
  27. //
  28. // Define the initialization file, the contents of which are run as the first
  29. // user mode process.
  30. //
  31. #define INITIALIZATION_COMMAND_FILE "config/init.set"
  32. //
  33. // Define the location of the OS base library, loaded into every user
  34. // application.
  35. //
  36. #define SYSTEM_OS_BASE_LIBRARY_PATH "system/" OS_BASE_LIBRARY
  37. //
  38. // Define the initially enforced maximum number of files.
  39. //
  40. #define INITIAL_MAX_FILE_COUNT 1024
  41. //
  42. // ----------------------------------------------- Internal Function Prototypes
  43. //
  44. KSTATUS
  45. PspAddIdleThread (
  46. PKPROCESS KernelProcess,
  47. PVOID IdleThreadStackBase,
  48. ULONG IdleThreadStackSize
  49. );
  50. //
  51. // ------------------------------------------------------ Data Type Definitions
  52. //
  53. //
  54. // -------------------------------------------------------------------- Globals
  55. //
  56. extern LIST_ENTRY PsProcessGroupList;
  57. PROCESS_GROUP PsKernelProcessGroup;
  58. //
  59. // Define the path from the system volume to the system directory. Set it to a
  60. // default in case there is no boot entry (which there should really always be).
  61. //
  62. PSTR PsSystemDirectoryPath = "minoca";
  63. //
  64. // Store the initial resource limits to set.
  65. //
  66. RESOURCE_LIMIT PsInitialResourceLimits[ResourceLimitCount] = {
  67. {0, RESOURCE_LIMIT_INFINITE}, // ResourceLimitCore
  68. {RESOURCE_LIMIT_INFINITE, RESOURCE_LIMIT_INFINITE}, // ResourceLimitCpuTime
  69. {RESOURCE_LIMIT_INFINITE, RESOURCE_LIMIT_INFINITE}, // ResourceLimitData
  70. {RESOURCE_LIMIT_INFINITE, RESOURCE_LIMIT_INFINITE}, // ResourceLimitFileSize
  71. {INITIAL_MAX_FILE_COUNT, OB_MAX_HANDLES}, // ResourceLimitFileCount
  72. {DEFAULT_USER_STACK_SIZE, RESOURCE_LIMIT_INFINITE}, // ResourceLimitStack
  73. {RESOURCE_LIMIT_INFINITE, RESOURCE_LIMIT_INFINITE}, // AddressSpace
  74. {RESOURCE_LIMIT_INFINITE, RESOURCE_LIMIT_INFINITE}, // ProcessCount
  75. {RESOURCE_LIMIT_INFINITE, RESOURCE_LIMIT_INFINITE}, // ResourceLimitSignals
  76. {0, 0} // ResourceLimitNice
  77. };
  78. //
  79. // ------------------------------------------------------------------ Functions
  80. //
  81. KSTATUS
  82. PsInitialize (
  83. ULONG Phase,
  84. PKERNEL_INITIALIZATION_BLOCK Parameters,
  85. PVOID IdleThreadStackBase,
  86. ULONG IdleThreadStackSize
  87. )
  88. /*++
  89. Routine Description:
  90. This routine initializes the process and thread subsystem.
  91. Arguments:
  92. Phase - Supplies the initialization phase. Valid values are 0 and 1.
  93. Parameters - Supplies an optional pointer to the kernel initialization
  94. block. It's only required for processor 0.
  95. IdleThreadStackBase - Supplies the base of the stack for the one thread
  96. currently running.
  97. IdleThreadStackSize - Supplies the size of the stack for the one thread
  98. currently running.
  99. Return Value:
  100. STATUS_SUCCESS on success.
  101. STATUS_INSUFFICIENT_RESOURCES if memory for the kernel process or thread
  102. could not be allocated.
  103. --*/
  104. {
  105. PBOOT_ENTRY BootEntry;
  106. PSTR KernelBinaryName;
  107. ULONG KernelBinaryNameSize;
  108. PSTR KernelNameCopy;
  109. PKPROCESS KernelProcess;
  110. RUNLEVEL OldRunLevel;
  111. ULONG Processor;
  112. KSTATUS Status;
  113. UINTN SystemDirectorySize;
  114. //
  115. // If this is the boot processor, initialize PS structures.
  116. //
  117. Processor = KeGetCurrentProcessorNumber();
  118. if (Phase == 0) {
  119. if (Processor == 0) {
  120. INITIALIZE_LIST_HEAD(&PsProcessListHead);
  121. PsProcessCount = 0;
  122. PsProcessListLock = KeCreateQueuedLock();
  123. if (PsProcessListLock == NULL) {
  124. Status = STATUS_INSUFFICIENT_RESOURCES;
  125. goto InitializeEnd;
  126. }
  127. Status = PspInitializeProcessGroupSupport();
  128. if (!KSUCCESS(Status)) {
  129. goto InitializeEnd;
  130. }
  131. //
  132. // Create the process object directory.
  133. //
  134. PsProcessDirectory = ObCreateObject(ObjectDirectory,
  135. NULL,
  136. "Process",
  137. sizeof("Process"),
  138. sizeof(OBJECT_HEADER),
  139. NULL,
  140. OBJECT_FLAG_USE_NAME_DIRECTLY,
  141. PS_ALLOCATION_TAG);
  142. if (PsProcessDirectory == NULL) {
  143. Status = STATUS_INSUFFICIENT_RESOURCES;
  144. goto InitializeEnd;
  145. }
  146. //
  147. // Create the kernel process.
  148. //
  149. KernelBinaryName = Parameters->KernelModule->BinaryName;
  150. KernelBinaryNameSize = RtlStringLength(KernelBinaryName) + 1;
  151. KernelNameCopy = MmAllocateNonPagedPool(KernelBinaryNameSize,
  152. PS_ALLOCATION_TAG);
  153. if (KernelNameCopy == NULL) {
  154. Status = STATUS_INSUFFICIENT_RESOURCES;
  155. goto InitializeEnd;
  156. }
  157. RtlStringCopy(KernelNameCopy,
  158. KernelBinaryName,
  159. KernelBinaryNameSize);
  160. KernelProcess = PspCreateProcess(KernelNameCopy,
  161. KernelBinaryNameSize,
  162. NULL,
  163. NULL,
  164. NULL,
  165. NULL,
  166. NULL,
  167. NULL);
  168. if (KernelProcess == NULL) {
  169. Status = STATUS_INSUFFICIENT_RESOURCES;
  170. goto InitializeEnd;
  171. }
  172. PsKernelProcess = KernelProcess;
  173. //
  174. // Copy the system directory path.
  175. //
  176. BootEntry = Parameters->BootEntry;
  177. if ((BootEntry != NULL) && (BootEntry->SystemPath != NULL)) {
  178. SystemDirectorySize =
  179. RtlStringLength(BootEntry->SystemPath) + 1;
  180. PsSystemDirectoryPath = MmAllocateNonPagedPool(
  181. SystemDirectorySize,
  182. PS_ALLOCATION_TAG);
  183. if (PsSystemDirectoryPath == NULL) {
  184. Status = STATUS_INSUFFICIENT_RESOURCES;
  185. goto InitializeEnd;
  186. }
  187. RtlStringCopy(PsSystemDirectoryPath,
  188. BootEntry->SystemPath,
  189. SystemDirectorySize);
  190. }
  191. PspInitializeUserLocking();
  192. } else {
  193. KernelProcess = PsKernelProcess;
  194. }
  195. //
  196. // Create the idle thread for this processor.
  197. //
  198. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  199. Status = PspAddIdleThread(KernelProcess,
  200. IdleThreadStackBase,
  201. IdleThreadStackSize);
  202. KeLowerRunLevel(OldRunLevel);
  203. if (!KSUCCESS(Status)) {
  204. goto InitializeEnd;
  205. }
  206. //
  207. // Perform one-time thread initialization.
  208. //
  209. if (Processor == 0) {
  210. Status = PspInitializeThreadSupport();
  211. if (!KSUCCESS(Status)) {
  212. goto InitializeEnd;
  213. }
  214. //
  215. // Give the kernel process it's own session (and process group).
  216. //
  217. ASSERT(KernelProcess->Identifiers.ProcessId == 0);
  218. PsKernelProcessGroup.ReferenceCount = 1;
  219. INITIALIZE_LIST_HEAD(&(PsKernelProcessGroup.ProcessListHead));
  220. INSERT_BEFORE(&(PsKernelProcessGroup.ListEntry),
  221. &PsProcessGroupList);
  222. }
  223. //
  224. // In phase 1, set up image support.
  225. //
  226. } else {
  227. ASSERT(Phase == 1);
  228. ASSERT(Processor == 0);
  229. Status = PspInitializeImageSupport(
  230. Parameters->KernelModule->LowestAddress,
  231. &(Parameters->ImageList));
  232. if (!KSUCCESS(Status)) {
  233. goto InitializeEnd;
  234. }
  235. }
  236. Status = STATUS_SUCCESS;
  237. InitializeEnd:
  238. return Status;
  239. }
  240. VOID
  241. PsVolumeArrival (
  242. PSTR VolumeName,
  243. ULONG VolumeNameLength,
  244. BOOL SystemVolume
  245. )
  246. /*++
  247. Routine Description:
  248. This routine implements actions that the process library takes in response
  249. to a new volume arrival.
  250. Arguments:
  251. VolumeName - Supplies the full path to the new volume.
  252. VolumeNameLength - Supplies the length of the volume name buffer, including
  253. the null terminator, in bytes.
  254. SystemVolume - Supplies a boolean indicating whether or not this is the
  255. system volume.
  256. Return Value:
  257. None.
  258. --*/
  259. {
  260. UINTN BytesRead;
  261. PSTR Command;
  262. PIO_HANDLE File;
  263. ULONGLONG FileSize;
  264. IO_BUFFER IoBuffer;
  265. PKPROCESS Process;
  266. KSTATUS Status;
  267. PIO_HANDLE SystemDirectory;
  268. PIO_HANDLE Volume;
  269. Command = NULL;
  270. File = NULL;
  271. SystemDirectory = NULL;
  272. Volume = NULL;
  273. //
  274. // Do nothing unless this is the system volume.
  275. //
  276. if (SystemVolume == FALSE) {
  277. Status = STATUS_SUCCESS;
  278. goto VolumeArrivalEnd;
  279. }
  280. //
  281. // Copy the system volume path. Synchronization would be needed if this
  282. // path changes.
  283. //
  284. ASSERT(VolumeNameLength != 0);
  285. Status = IoOpen(TRUE,
  286. NULL,
  287. VolumeName,
  288. VolumeNameLength,
  289. IO_ACCESS_READ,
  290. OPEN_FLAG_DIRECTORY,
  291. 0,
  292. &Volume);
  293. if (!KSUCCESS(Status)) {
  294. RtlDebugPrint("Failed to open system volume: %d\n", Status);
  295. goto VolumeArrivalEnd;
  296. }
  297. //
  298. // Attempt to open the system directory.
  299. //
  300. Status = IoOpen(TRUE,
  301. Volume,
  302. PsSystemDirectoryPath,
  303. RtlStringLength(PsSystemDirectoryPath) + 1,
  304. IO_ACCESS_READ,
  305. OPEN_FLAG_DIRECTORY,
  306. 0,
  307. &SystemDirectory);
  308. if (!KSUCCESS(Status)) {
  309. RtlDebugPrint("Failed to open system directory '%s': %d\n",
  310. PsSystemDirectoryPath,
  311. Status);
  312. goto VolumeArrivalEnd;
  313. }
  314. //
  315. // Attempt to open the OS base library.
  316. //
  317. Status = IoOpen(TRUE,
  318. SystemDirectory,
  319. SYSTEM_OS_BASE_LIBRARY_PATH,
  320. sizeof(SYSTEM_OS_BASE_LIBRARY_PATH),
  321. IO_ACCESS_READ | IO_ACCESS_EXECUTE,
  322. 0,
  323. FILE_PERMISSION_NONE,
  324. &PsOsBaseLibrary);
  325. if (!KSUCCESS(Status)) {
  326. RtlDebugPrint("Failed to open OS base library '%s/%s': %d\n",
  327. PsSystemDirectoryPath,
  328. SYSTEM_OS_BASE_LIBRARY_PATH,
  329. Status);
  330. goto VolumeArrivalEnd;
  331. }
  332. //
  333. // Attempt to open the initialization command file.
  334. //
  335. Status = IoOpen(TRUE,
  336. SystemDirectory,
  337. INITIALIZATION_COMMAND_FILE,
  338. sizeof(INITIALIZATION_COMMAND_FILE),
  339. IO_ACCESS_READ,
  340. 0,
  341. FILE_PERMISSION_NONE,
  342. &File);
  343. if (!KSUCCESS(Status)) {
  344. goto VolumeArrivalEnd;
  345. }
  346. Status = IoGetFileSize(File, &FileSize);
  347. if (!KSUCCESS(Status)) {
  348. goto VolumeArrivalEnd;
  349. }
  350. if (FileSize > (UINTN)FileSize) {
  351. Status = STATUS_BUFFER_OVERRUN;
  352. goto VolumeArrivalEnd;
  353. }
  354. //
  355. // Create an I/O buffer from paged pool so that a contiguous virtual buffer
  356. // can be supplied to process creation.
  357. //
  358. Command = MmAllocatePagedPool(FileSize, PS_ALLOCATION_TAG);
  359. if (Command == NULL) {
  360. Status = STATUS_INSUFFICIENT_RESOURCES;
  361. goto VolumeArrivalEnd;
  362. }
  363. Status = MmInitializeIoBuffer(&IoBuffer,
  364. Command,
  365. INVALID_PHYSICAL_ADDRESS,
  366. FileSize,
  367. IO_BUFFER_FLAG_KERNEL_MODE_DATA);
  368. if (!KSUCCESS(Status)) {
  369. goto VolumeArrivalEnd;
  370. }
  371. Status = IoRead(File,
  372. &IoBuffer,
  373. (UINTN)FileSize,
  374. 0,
  375. WAIT_TIME_INDEFINITE,
  376. &BytesRead);
  377. if (!KSUCCESS(Status)) {
  378. goto VolumeArrivalEnd;
  379. }
  380. if (BytesRead != FileSize) {
  381. Status = STATUS_DATA_LENGTH_MISMATCH;
  382. goto VolumeArrivalEnd;
  383. }
  384. Command[FileSize] = '\0';
  385. //
  386. // Fire up the process.
  387. //
  388. Process = PsCreateProcess(Command,
  389. (ULONG)FileSize + 1,
  390. NULL,
  391. IoGetPathPoint(Volume),
  392. NULL);
  393. if (Process == NULL) {
  394. RtlDebugPrint("Failed to create initial process: \"%s\"\n",
  395. Command);
  396. goto VolumeArrivalEnd;
  397. }
  398. //
  399. // Release the reference on the process, as no one is waiting around for
  400. // its completion.
  401. //
  402. ObReleaseReference(Process);
  403. VolumeArrivalEnd:
  404. if (Volume != NULL) {
  405. IoClose(Volume);
  406. }
  407. if (SystemDirectory != NULL) {
  408. IoClose(SystemDirectory);
  409. }
  410. if (File != NULL) {
  411. IoClose(File);
  412. }
  413. return;
  414. }
  415. //
  416. // --------------------------------------------------------- Internal Functions
  417. //
  418. KSTATUS
  419. PspAddIdleThread (
  420. PKPROCESS KernelProcess,
  421. PVOID IdleThreadStackBase,
  422. ULONG IdleThreadStackSize
  423. )
  424. /*++
  425. Routine Description:
  426. This routine adds the processor's initial thread to the thread accounting
  427. system.
  428. Arguments:
  429. KernelProcess - Supplies a pointer to the system process.
  430. IdleThreadStackBase - Supplies the base of the stack for the one thread
  431. currently running on this processor.
  432. IdleThreadStackSize - Supplies the size of the stack for the one thread
  433. currently running on this processor.
  434. Return Value:
  435. STATUS_SUCCESS on success.
  436. STATUS_INSUFFICIENT_RESOURCES if memory for the thread could not be
  437. allocated.
  438. --*/
  439. {
  440. PKTHREAD CurrentThread;
  441. CHAR Name[IDLE_THREAD_NAME_LENGTH];
  442. PPROCESSOR_BLOCK Processor;
  443. KSTATUS Status;
  444. ASSERT(KeGetRunLevel() >= RunLevelDispatch);
  445. CurrentThread = NULL;
  446. Processor = KeGetCurrentProcessorBlock();
  447. RtlPrintToString(Name,
  448. IDLE_THREAD_NAME_LENGTH,
  449. CharacterEncodingDefault,
  450. "Idle%d",
  451. Processor->ProcessorNumber);
  452. //
  453. // Manually create the idle thread. Locks don't need to be acquired here
  454. // because preemption has not yet been turned on.
  455. //
  456. CurrentThread = ObCreateObject(ObjectThread,
  457. KernelProcess,
  458. Name,
  459. IDLE_THREAD_NAME_LENGTH,
  460. sizeof(KTHREAD),
  461. NULL,
  462. 0,
  463. PS_ALLOCATION_TAG);
  464. if (CurrentThread == NULL) {
  465. Status = STATUS_INSUFFICIENT_RESOURCES;
  466. goto AddIdleThreadEnd;
  467. }
  468. //
  469. // Initialize pieces of the thread.
  470. //
  471. CurrentThread->OwningProcess = KernelProcess;
  472. CurrentThread->ThreadId = RtlAtomicAdd32((PULONG)&PsNextThreadId, 1);
  473. CurrentThread->KernelStack = IdleThreadStackBase;
  474. CurrentThread->KernelStackSize = IdleThreadStackSize;
  475. CurrentThread->State = ThreadStateRunning;
  476. CurrentThread->SchedulerEntry.Type = SchedulerEntryThread;
  477. CurrentThread->SchedulerEntry.Parent = &(Processor->Scheduler.Group.Entry);
  478. CurrentThread->ThreadPointer = PsInitialThreadPointer;
  479. CurrentThread->BuiltinWaitBlock = ObCreateWaitBlock(0);
  480. if (CurrentThread->BuiltinWaitBlock == NULL) {
  481. Status = STATUS_INSUFFICIENT_RESOURCES;
  482. goto AddIdleThreadEnd;
  483. }
  484. INSERT_BEFORE(&(CurrentThread->ProcessEntry),
  485. &(KernelProcess->ThreadListHead));
  486. KernelProcess->ThreadCount += 1;
  487. //
  488. // Make this initial thread all-powerful.
  489. //
  490. CurrentThread->Permissions.Limit = PERMISSION_SET_FULL;
  491. CurrentThread->Permissions.Permitted = PERMISSION_SET_FULL;
  492. CurrentThread->Permissions.Inheritable = PERMISSION_SET_FULL;
  493. CurrentThread->Permissions.Effective = PERMISSION_SET_FULL;
  494. RtlCopyMemory(&(CurrentThread->Limits),
  495. PsInitialResourceLimits,
  496. sizeof(CurrentThread->Limits));
  497. //
  498. // Again, it's okay not to raise the run-level because preemption is not
  499. // yet enabled in the system.
  500. //
  501. Processor->RunningThread = CurrentThread;
  502. //
  503. // Set this thread as the idle thread.
  504. //
  505. Processor->IdleThread = CurrentThread;
  506. Status = STATUS_SUCCESS;
  507. AddIdleThreadEnd:
  508. if (!KSUCCESS(Status)) {
  509. if (CurrentThread != NULL) {
  510. if (CurrentThread->BuiltinTimer != NULL) {
  511. KeDestroyTimer(CurrentThread->BuiltinTimer);
  512. }
  513. if (CurrentThread->BuiltinWaitBlock != NULL) {
  514. ObDestroyWaitBlock(CurrentThread->BuiltinWaitBlock);
  515. }
  516. ObReleaseReference(CurrentThread);
  517. }
  518. }
  519. return Status;
  520. }