init.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  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. Status = PspInitializeUtsRealm(KernelProcess);
  173. if (!KSUCCESS(Status)) {
  174. goto InitializeEnd;
  175. }
  176. PsKernelProcess = KernelProcess;
  177. //
  178. // Copy the system directory path.
  179. //
  180. BootEntry = Parameters->BootEntry;
  181. if ((BootEntry != NULL) && (BootEntry->SystemPath != NULL)) {
  182. SystemDirectorySize =
  183. RtlStringLength(BootEntry->SystemPath) + 1;
  184. PsSystemDirectoryPath = MmAllocateNonPagedPool(
  185. SystemDirectorySize,
  186. PS_ALLOCATION_TAG);
  187. if (PsSystemDirectoryPath == NULL) {
  188. Status = STATUS_INSUFFICIENT_RESOURCES;
  189. goto InitializeEnd;
  190. }
  191. RtlStringCopy(PsSystemDirectoryPath,
  192. BootEntry->SystemPath,
  193. SystemDirectorySize);
  194. }
  195. PspInitializeUserLocking();
  196. } else {
  197. KernelProcess = PsKernelProcess;
  198. }
  199. //
  200. // Create the idle thread for this processor.
  201. //
  202. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  203. Status = PspAddIdleThread(KernelProcess,
  204. IdleThreadStackBase,
  205. IdleThreadStackSize);
  206. KeLowerRunLevel(OldRunLevel);
  207. if (!KSUCCESS(Status)) {
  208. goto InitializeEnd;
  209. }
  210. //
  211. // Perform one-time thread initialization.
  212. //
  213. if (Processor == 0) {
  214. Status = PspInitializeThreadSupport();
  215. if (!KSUCCESS(Status)) {
  216. goto InitializeEnd;
  217. }
  218. //
  219. // Give the kernel process it's own session (and process group).
  220. //
  221. ASSERT(KernelProcess->Identifiers.ProcessId == 0);
  222. PsKernelProcessGroup.ReferenceCount = 1;
  223. INITIALIZE_LIST_HEAD(&(PsKernelProcessGroup.ProcessListHead));
  224. INSERT_BEFORE(&(PsKernelProcessGroup.ListEntry),
  225. &PsProcessGroupList);
  226. }
  227. //
  228. // In phase 1, set up image support.
  229. //
  230. } else {
  231. ASSERT(Phase == 1);
  232. ASSERT(Processor == 0);
  233. Status = PspInitializeImageSupport(
  234. Parameters->KernelModule->LowestAddress,
  235. &(Parameters->ImageList));
  236. if (!KSUCCESS(Status)) {
  237. goto InitializeEnd;
  238. }
  239. }
  240. Status = STATUS_SUCCESS;
  241. InitializeEnd:
  242. return Status;
  243. }
  244. VOID
  245. PsVolumeArrival (
  246. PCSTR VolumeName,
  247. ULONG VolumeNameLength,
  248. BOOL SystemVolume
  249. )
  250. /*++
  251. Routine Description:
  252. This routine implements actions that the process library takes in response
  253. to a new volume arrival.
  254. Arguments:
  255. VolumeName - Supplies the full path to the new volume.
  256. VolumeNameLength - Supplies the length of the volume name buffer, including
  257. the null terminator, in bytes.
  258. SystemVolume - Supplies a boolean indicating whether or not this is the
  259. system volume.
  260. Return Value:
  261. None.
  262. --*/
  263. {
  264. UINTN BytesRead;
  265. PSTR Command;
  266. PIO_HANDLE File;
  267. ULONGLONG FileSize;
  268. IO_BUFFER IoBuffer;
  269. PKPROCESS Process;
  270. KSTATUS Status;
  271. PIO_HANDLE SystemDirectory;
  272. PIO_HANDLE Volume;
  273. Command = NULL;
  274. File = NULL;
  275. SystemDirectory = NULL;
  276. Volume = NULL;
  277. //
  278. // Do nothing unless this is the system volume.
  279. //
  280. if (SystemVolume == FALSE) {
  281. Status = STATUS_SUCCESS;
  282. goto VolumeArrivalEnd;
  283. }
  284. //
  285. // Copy the system volume path. Synchronization would be needed if this
  286. // path changes.
  287. //
  288. ASSERT(VolumeNameLength != 0);
  289. Status = IoOpen(TRUE,
  290. NULL,
  291. VolumeName,
  292. VolumeNameLength,
  293. IO_ACCESS_READ,
  294. OPEN_FLAG_DIRECTORY,
  295. 0,
  296. &Volume);
  297. if (!KSUCCESS(Status)) {
  298. RtlDebugPrint("Failed to open system volume: %d\n", Status);
  299. goto VolumeArrivalEnd;
  300. }
  301. //
  302. // Attempt to open the system directory.
  303. //
  304. Status = IoOpen(TRUE,
  305. Volume,
  306. PsSystemDirectoryPath,
  307. RtlStringLength(PsSystemDirectoryPath) + 1,
  308. IO_ACCESS_READ,
  309. OPEN_FLAG_DIRECTORY,
  310. 0,
  311. &SystemDirectory);
  312. if (!KSUCCESS(Status)) {
  313. RtlDebugPrint("Failed to open system directory '%s': %d\n",
  314. PsSystemDirectoryPath,
  315. Status);
  316. goto VolumeArrivalEnd;
  317. }
  318. //
  319. // Attempt to open the OS base library.
  320. //
  321. Status = IoOpen(TRUE,
  322. SystemDirectory,
  323. SYSTEM_OS_BASE_LIBRARY_PATH,
  324. sizeof(SYSTEM_OS_BASE_LIBRARY_PATH),
  325. IO_ACCESS_READ | IO_ACCESS_EXECUTE,
  326. 0,
  327. FILE_PERMISSION_NONE,
  328. &PsOsBaseLibrary);
  329. if (!KSUCCESS(Status)) {
  330. RtlDebugPrint("Failed to open OS base library '%s/%s': %d\n",
  331. PsSystemDirectoryPath,
  332. SYSTEM_OS_BASE_LIBRARY_PATH,
  333. Status);
  334. goto VolumeArrivalEnd;
  335. }
  336. //
  337. // Attempt to open the initialization command file.
  338. //
  339. Status = IoOpen(TRUE,
  340. SystemDirectory,
  341. INITIALIZATION_COMMAND_FILE,
  342. sizeof(INITIALIZATION_COMMAND_FILE),
  343. IO_ACCESS_READ,
  344. 0,
  345. FILE_PERMISSION_NONE,
  346. &File);
  347. if (!KSUCCESS(Status)) {
  348. goto VolumeArrivalEnd;
  349. }
  350. Status = IoGetFileSize(File, &FileSize);
  351. if (!KSUCCESS(Status)) {
  352. goto VolumeArrivalEnd;
  353. }
  354. if (FileSize > (UINTN)FileSize) {
  355. Status = STATUS_BUFFER_OVERRUN;
  356. goto VolumeArrivalEnd;
  357. }
  358. //
  359. // Create an I/O buffer from paged pool so that a contiguous virtual buffer
  360. // can be supplied to process creation.
  361. //
  362. Command = MmAllocatePagedPool(FileSize, PS_ALLOCATION_TAG);
  363. if (Command == NULL) {
  364. Status = STATUS_INSUFFICIENT_RESOURCES;
  365. goto VolumeArrivalEnd;
  366. }
  367. Status = MmInitializeIoBuffer(&IoBuffer,
  368. Command,
  369. INVALID_PHYSICAL_ADDRESS,
  370. FileSize,
  371. IO_BUFFER_FLAG_KERNEL_MODE_DATA);
  372. if (!KSUCCESS(Status)) {
  373. goto VolumeArrivalEnd;
  374. }
  375. Status = IoRead(File,
  376. &IoBuffer,
  377. (UINTN)FileSize,
  378. 0,
  379. WAIT_TIME_INDEFINITE,
  380. &BytesRead);
  381. if (!KSUCCESS(Status)) {
  382. goto VolumeArrivalEnd;
  383. }
  384. if (BytesRead != FileSize) {
  385. Status = STATUS_DATA_LENGTH_MISMATCH;
  386. goto VolumeArrivalEnd;
  387. }
  388. Command[FileSize] = '\0';
  389. //
  390. // Fire up the process.
  391. //
  392. Process = PsCreateProcess(Command,
  393. (ULONG)FileSize + 1,
  394. NULL,
  395. IoGetPathPoint(Volume),
  396. NULL);
  397. if (Process == NULL) {
  398. RtlDebugPrint("Failed to create initial process: \"%s\"\n",
  399. Command);
  400. goto VolumeArrivalEnd;
  401. }
  402. //
  403. // Release the reference on the process, as no one is waiting around for
  404. // its completion.
  405. //
  406. ObReleaseReference(Process);
  407. VolumeArrivalEnd:
  408. if (Volume != NULL) {
  409. IoClose(Volume);
  410. }
  411. if (SystemDirectory != NULL) {
  412. IoClose(SystemDirectory);
  413. }
  414. if (File != NULL) {
  415. IoClose(File);
  416. }
  417. return;
  418. }
  419. //
  420. // --------------------------------------------------------- Internal Functions
  421. //
  422. KSTATUS
  423. PspAddIdleThread (
  424. PKPROCESS KernelProcess,
  425. PVOID IdleThreadStackBase,
  426. ULONG IdleThreadStackSize
  427. )
  428. /*++
  429. Routine Description:
  430. This routine adds the processor's initial thread to the thread accounting
  431. system.
  432. Arguments:
  433. KernelProcess - Supplies a pointer to the system process.
  434. IdleThreadStackBase - Supplies the base of the stack for the one thread
  435. currently running on this processor.
  436. IdleThreadStackSize - Supplies the size of the stack for the one thread
  437. currently running on this processor.
  438. Return Value:
  439. STATUS_SUCCESS on success.
  440. STATUS_INSUFFICIENT_RESOURCES if memory for the thread could not be
  441. allocated.
  442. --*/
  443. {
  444. PKTHREAD CurrentThread;
  445. CHAR Name[IDLE_THREAD_NAME_LENGTH];
  446. PPROCESSOR_BLOCK Processor;
  447. KSTATUS Status;
  448. ASSERT(KeGetRunLevel() >= RunLevelDispatch);
  449. CurrentThread = NULL;
  450. Processor = KeGetCurrentProcessorBlock();
  451. RtlPrintToString(Name,
  452. IDLE_THREAD_NAME_LENGTH,
  453. CharacterEncodingDefault,
  454. "Idle%d",
  455. Processor->ProcessorNumber);
  456. //
  457. // Manually create the idle thread. Locks don't need to be acquired here
  458. // because preemption has not yet been turned on.
  459. //
  460. CurrentThread = ObCreateObject(ObjectThread,
  461. KernelProcess,
  462. Name,
  463. IDLE_THREAD_NAME_LENGTH,
  464. sizeof(KTHREAD),
  465. NULL,
  466. 0,
  467. PS_ALLOCATION_TAG);
  468. if (CurrentThread == NULL) {
  469. Status = STATUS_INSUFFICIENT_RESOURCES;
  470. goto AddIdleThreadEnd;
  471. }
  472. //
  473. // Initialize pieces of the thread.
  474. //
  475. CurrentThread->OwningProcess = KernelProcess;
  476. CurrentThread->ThreadId = RtlAtomicAdd32((PULONG)&PsNextThreadId, 1);
  477. CurrentThread->KernelStack = IdleThreadStackBase;
  478. CurrentThread->KernelStackSize = IdleThreadStackSize;
  479. CurrentThread->State = ThreadStateRunning;
  480. CurrentThread->SchedulerEntry.Type = SchedulerEntryThread;
  481. CurrentThread->SchedulerEntry.Parent = &(Processor->Scheduler.Group.Entry);
  482. CurrentThread->ThreadPointer = PsInitialThreadPointer;
  483. CurrentThread->BuiltinWaitBlock = ObCreateWaitBlock(0);
  484. if (CurrentThread->BuiltinWaitBlock == NULL) {
  485. Status = STATUS_INSUFFICIENT_RESOURCES;
  486. goto AddIdleThreadEnd;
  487. }
  488. INSERT_BEFORE(&(CurrentThread->ProcessEntry),
  489. &(KernelProcess->ThreadListHead));
  490. KernelProcess->ThreadCount += 1;
  491. //
  492. // Make this initial thread all-powerful.
  493. //
  494. CurrentThread->Permissions.Limit = PERMISSION_SET_FULL;
  495. CurrentThread->Permissions.Permitted = PERMISSION_SET_FULL;
  496. CurrentThread->Permissions.Inheritable = PERMISSION_SET_FULL;
  497. CurrentThread->Permissions.Effective = PERMISSION_SET_FULL;
  498. RtlCopyMemory(&(CurrentThread->Limits),
  499. PsInitialResourceLimits,
  500. sizeof(CurrentThread->Limits));
  501. //
  502. // Again, it's okay not to raise the run-level because preemption is not
  503. // yet enabled in the system.
  504. //
  505. Processor->RunningThread = CurrentThread;
  506. //
  507. // Set this thread as the idle thread.
  508. //
  509. Processor->IdleThread = CurrentThread;
  510. Status = STATUS_SUCCESS;
  511. AddIdleThreadEnd:
  512. if (!KSUCCESS(Status)) {
  513. if (CurrentThread != NULL) {
  514. if (CurrentThread->BuiltinTimer != NULL) {
  515. KeDestroyTimer(CurrentThread->BuiltinTimer);
  516. }
  517. if (CurrentThread->BuiltinWaitBlock != NULL) {
  518. ObDestroyWaitBlock(CurrentThread->BuiltinWaitBlock);
  519. }
  520. ObReleaseReference(CurrentThread);
  521. }
  522. }
  523. return Status;
  524. }