bootman.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. /*++
  2. Copyright (c) 2014 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. bootman.c
  5. Abstract:
  6. This module loads the selected operating system loader into memory and
  7. jumps to it.
  8. Author:
  9. Evan Green 21-Feb-2014
  10. Environment:
  11. Boot
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include <minoca/kernel/kernel.h>
  17. #include <minoca/lib/fat/fat.h>
  18. #include "firmware.h"
  19. #include "bootlib.h"
  20. #include <minoca/lib/basevid.h>
  21. #include "bootman.h"
  22. //
  23. // ---------------------------------------------------------------- Definitions
  24. //
  25. #define BOOT_MANAGER_BINARY_NAME_MAX_SIZE 16
  26. #define BOOT_MANAGER_MODULE_BUFFER_SIZE \
  27. (sizeof(DEBUG_MODULE) + sizeof(BOOT_MANAGER_BINARY_NAME_MAX_SIZE))
  28. #define BOOT_MANAGER_NAME "Minoca Boot Manager"
  29. //
  30. // ----------------------------------------------- Internal Function Prototypes
  31. //
  32. KSTATUS
  33. BmpLoadBootConfiguration (
  34. PVOID BootDevice,
  35. PBOOT_CONFIGURATION_CONTEXT Context,
  36. PBOOT_ENTRY *SelectedBootEntry
  37. );
  38. //
  39. // ------------------------------------------------------ Data Type Definitions
  40. //
  41. //
  42. // -------------------------------------------------------------------- Globals
  43. //
  44. //
  45. // Set this to TRUE to enable debugging in the boot manager.
  46. //
  47. BOOL BmDebug = FALSE;
  48. DEBUG_MODULE BmModule;
  49. LIST_ENTRY BmLoadedImageList;
  50. //
  51. // Carve off memory to store the loader module, including its string.
  52. //
  53. UCHAR BmModuleBuffer[BOOT_MANAGER_MODULE_BUFFER_SIZE];
  54. //
  55. // ------------------------------------------------------------------ Functions
  56. //
  57. INT
  58. BmMain (
  59. PBOOT_INITIALIZATION_BLOCK Parameters
  60. )
  61. /*++
  62. Routine Description:
  63. This routine is the entry point for the boot manager program.
  64. Arguments:
  65. Parameters - Supplies a pointer to the application parameters.
  66. Return Value:
  67. On success, this function does not return.
  68. On failure, this function returns the step number on which it failed. This
  69. provides an indication as to where in the boot process it failed.
  70. --*/
  71. {
  72. INT ApplicationReturn;
  73. UINTN BaseDifference;
  74. BOOT_CONFIGURATION_CONTEXT BootConfigurationContext;
  75. PBOOT_VOLUME BootDevice;
  76. PBOOT_ENTRY BootEntry;
  77. PDEBUG_DEVICE_DESCRIPTION DebugDevice;
  78. PDEBUG_MODULE DebugModule;
  79. PLOADED_IMAGE LoaderImage;
  80. PSTR LoaderName;
  81. UINTN LoaderNameSize;
  82. PBOOT_INITIALIZATION_BLOCK LoaderParameters;
  83. ULONG LoadFlags;
  84. ULONG ModuleNameLength;
  85. PBOOT_VOLUME OsDevice;
  86. KSTATUS Status;
  87. ULONG Step;
  88. BootDevice = NULL;
  89. DebugDevice = NULL;
  90. LoaderParameters = NULL;
  91. Step = 0;
  92. //
  93. // Perform just enough firmware initialization to get to the debugger. Not
  94. // much happens here, as this is all undebuggable.
  95. //
  96. Status = FwInitialize(0, Parameters);
  97. if (!KSUCCESS(Status)) {
  98. goto MainEnd;
  99. }
  100. //
  101. // Perform very basic processor initialization, preparing it to take
  102. // exceptions and use the serial port.
  103. //
  104. Step += 1;
  105. BoInitializeProcessor();
  106. Step += 1;
  107. BoHlBootInitialize(&DebugDevice, NULL);
  108. if (BoFirmwareDebugDevice != NULL) {
  109. DebugDevice = BoFirmwareDebugDevice;
  110. }
  111. Step += 1;
  112. DebugModule = (PDEBUG_MODULE)BmModuleBuffer;
  113. //
  114. // Initialize the debugging subsystem.
  115. //
  116. RtlZeroMemory(&BmModuleBuffer, sizeof(BmModuleBuffer));
  117. ModuleNameLength = RtlStringLength(Parameters->ApplicationName) + 1;
  118. if (ModuleNameLength > BOOT_MANAGER_BINARY_NAME_MAX_SIZE) {
  119. ModuleNameLength = BOOT_MANAGER_BINARY_NAME_MAX_SIZE;
  120. }
  121. DebugModule->StructureSize = sizeof(DEBUG_MODULE) + ModuleNameLength -
  122. (ANYSIZE_ARRAY * sizeof(CHAR));
  123. RtlStringCopy(DebugModule->BinaryName,
  124. Parameters->ApplicationName,
  125. ModuleNameLength);
  126. DebugModule->BaseAddress = Parameters->ApplicationBaseAddress;
  127. DebugModule->LowestAddress = Parameters->ApplicationLowestAddress;
  128. DebugModule->Size = Parameters->ApplicationSize;
  129. BoProductName = BOOT_MANAGER_NAME;
  130. if (BmDebug != FALSE) {
  131. Status = KdInitialize(DebugDevice, DebugModule);
  132. if (!KSUCCESS(Status)) {
  133. goto MainEnd;
  134. }
  135. }
  136. //
  137. // Initialize the firmware layer.
  138. //
  139. Step += 1;
  140. Status = FwInitialize(1, Parameters);
  141. if (!KSUCCESS(Status)) {
  142. goto MainEnd;
  143. }
  144. //
  145. // Mount the boot device.
  146. //
  147. Step += 1;
  148. Status = BoOpenBootVolume(Parameters->DriveNumber,
  149. Parameters->PartitionOffset,
  150. NULL,
  151. &BootDevice);
  152. if (!KSUCCESS(Status)) {
  153. FwPrintString(0, 0, "Failed to open boot volume.");
  154. goto MainEnd;
  155. }
  156. //
  157. // Load the boot configuration information.
  158. //
  159. Step += 1;
  160. Status = BmpLoadBootConfiguration(BootDevice,
  161. &BootConfigurationContext,
  162. &BootEntry);
  163. if (!KSUCCESS(Status)) {
  164. FwPrintString(0, 0, "Failed to load Boot Configuration.");
  165. goto MainEnd;
  166. }
  167. //
  168. // Close the boot volume and open the OS volume. It is possible these are
  169. // the same.
  170. //
  171. Step += 1;
  172. Status = BoCloseVolume(BootDevice);
  173. BootDevice = NULL;
  174. if (!KSUCCESS(Status)) {
  175. goto MainEnd;
  176. }
  177. Step += 1;
  178. if (BootEntry == NULL) {
  179. FwPrintString(0, 0, "No boot entry selected.");
  180. Status = STATUS_NO_DATA_AVAILABLE;
  181. goto MainEnd;
  182. }
  183. Step += 1;
  184. Status = BoOpenVolume(BootEntry->PartitionId, &OsDevice);
  185. if (!KSUCCESS(Status)) {
  186. FwPrintString(0, 0, "Failed to open OS volume.");
  187. goto MainEnd;
  188. }
  189. //
  190. // Load the loader.
  191. //
  192. Step += 1;
  193. Status = BmpInitializeImageSupport(OsDevice, BootEntry);
  194. if (!KSUCCESS(Status)) {
  195. goto MainEnd;
  196. }
  197. LoaderName = BootEntry->LoaderPath;
  198. LoaderNameSize = RtlStringLength(BootEntry->LoaderPath);
  199. LoadFlags = IMAGE_LOAD_FLAG_IGNORE_INTERPRETER |
  200. IMAGE_LOAD_FLAG_PRIMARY_EXECUTABLE |
  201. IMAGE_LOAD_FLAG_NO_STATIC_CONSTRUCTORS |
  202. IMAGE_LOAD_FLAG_BIND_NOW;
  203. Status = ImLoadExecutable(&BmLoadedImageList,
  204. BootEntry->LoaderPath,
  205. NULL,
  206. NULL,
  207. NULL,
  208. LoadFlags,
  209. 0,
  210. &LoaderImage,
  211. NULL);
  212. if (!KSUCCESS(Status)) {
  213. FwPrintString(0, 0, "Failed to load OS loader.");
  214. goto MainEnd;
  215. }
  216. //
  217. // Initialize the boot parameters.
  218. //
  219. Step += 1;
  220. LoaderParameters = BoAllocateMemory(sizeof(BOOT_INITIALIZATION_BLOCK));
  221. if (LoaderParameters == NULL) {
  222. Status = STATUS_INSUFFICIENT_RESOURCES;
  223. goto MainEnd;
  224. }
  225. Step += 1;
  226. RtlZeroMemory(LoaderParameters, sizeof(BOOT_INITIALIZATION_BLOCK));
  227. LoaderParameters->Version = BOOT_INITIALIZATION_BLOCK_VERSION;
  228. LoaderParameters->BootConfigurationFile = BootConfigurationContext.FileData;
  229. LoaderParameters->BootConfigurationFileSize =
  230. BootConfigurationContext.FileDataSize;
  231. LoaderParameters->BootEntryId = BootEntry->Id;
  232. LoaderParameters->BootEntryFlags = BootEntry->Flags;
  233. LoaderParameters->StackTop = Parameters->StackTop;
  234. LoaderParameters->StackSize = Parameters->StackSize;
  235. LoaderParameters->Flags = Parameters->Flags |
  236. BOOT_INITIALIZATION_FLAG_SCREEN_CLEAR;
  237. BaseDifference = (UINTN)LoaderImage->LoadedLowestAddress -
  238. (UINTN)LoaderImage->PreferredLowestAddress;
  239. //
  240. // Set the file name and base address of the loader.
  241. //
  242. LoaderParameters->ApplicationName =
  243. RtlStringFindCharacterRight(LoaderName, '/', LoaderNameSize);
  244. if (LoaderParameters->ApplicationName == NULL) {
  245. LoaderParameters->ApplicationName = LoaderName;
  246. } else {
  247. LoaderParameters->ApplicationName += 1;
  248. }
  249. LoaderParameters->ApplicationBaseAddress = LoaderImage->DeclaredBase +
  250. BaseDifference;
  251. LoaderParameters->ApplicationLowestAddress =
  252. LoaderImage->LoadedLowestAddress;
  253. LoaderParameters->ApplicationSize = LoaderImage->Size;
  254. LoaderParameters->ApplicationArguments = BootEntry->LoaderArguments;
  255. Status = BmpFwInitializeBootBlock(LoaderParameters, OsDevice);
  256. if (!KSUCCESS(Status)) {
  257. goto MainEnd;
  258. }
  259. Step += 1;
  260. Status = BoCloseVolume(OsDevice);
  261. if (!KSUCCESS(Status)) {
  262. goto MainEnd;
  263. }
  264. Step += 1;
  265. KdDisconnect();
  266. //
  267. // Launch the boot application. Hopefully this does not return.
  268. //
  269. Step += 1;
  270. ApplicationReturn = BmpFwTransferToBootApplication(LoaderParameters,
  271. LoaderImage->EntryPoint);
  272. Step += 1;
  273. //
  274. // The loader prints on the first two lines, so leave those alone.
  275. //
  276. FwPrintString(0, 3, "Boot Application returned ");
  277. FwPrintHexInteger(26, 3, ApplicationReturn);
  278. //
  279. // Unload the image.
  280. //
  281. ImImageReleaseReference(LoaderImage);
  282. LoaderImage = NULL;
  283. //
  284. // Destroy the initialization block.
  285. //
  286. if (LoaderParameters != NULL) {
  287. if (LoaderParameters->ReservedRegions != NULL) {
  288. BoFreeMemory(LoaderParameters->ReservedRegions);
  289. }
  290. BoFreeMemory(LoaderParameters);
  291. LoaderParameters = NULL;
  292. }
  293. Status = STATUS_SUCCESS;
  294. MainEnd:
  295. //
  296. // The loader prints on the first two lines, and the "application returned"
  297. // message occurs on the third, so start on the fourth.
  298. //
  299. FwPrintString(0, 4, "Boot Manager Failed: ");
  300. FwPrintHexInteger(21, 4, Status);
  301. FwPrintString(0, 5, "Step: ");
  302. FwPrintInteger(6, 5, Step);
  303. FwDestroy();
  304. return Step;
  305. }
  306. PVOID
  307. BoExpandHeap (
  308. PMEMORY_HEAP Heap,
  309. UINTN Size,
  310. UINTN Tag
  311. )
  312. /*++
  313. Routine Description:
  314. This routine is called when the heap wants to expand and get more space.
  315. Arguments:
  316. Heap - Supplies a pointer to the heap to allocate from.
  317. Size - Supplies the size of the allocation request, in bytes.
  318. Tag - Supplies a 32-bit tag to associate with this allocation for debugging
  319. purposes. These are usually four ASCII characters so as to stand out
  320. when a poor developer is looking at a raw memory dump. It could also be
  321. a return address.
  322. Return Value:
  323. Returns a pointer to the allocation if successful, or NULL if the
  324. allocation failed.
  325. --*/
  326. {
  327. ULONG AllocationSize;
  328. ULONG PageSize;
  329. PHYSICAL_ADDRESS PhysicalAddress;
  330. PVOID PhysicalPointer;
  331. KSTATUS Status;
  332. PhysicalPointer = NULL;
  333. if (Size == 0) {
  334. return NULL;
  335. }
  336. PageSize = MmPageSize();
  337. //
  338. // Attempt to allocate new pages to satisfy the allocation.
  339. //
  340. AllocationSize = ALIGN_RANGE_UP(Size, PageSize);
  341. Status = FwAllocatePages(&PhysicalAddress,
  342. AllocationSize,
  343. PageSize,
  344. MemoryTypeLoaderTemporary);
  345. if (!KSUCCESS(Status)) {
  346. goto ExpandHeapEnd;
  347. }
  348. ASSERT((UINTN)PhysicalAddress == PhysicalAddress);
  349. PhysicalPointer = (PVOID)(UINTN)PhysicalAddress;
  350. ExpandHeapEnd:
  351. return PhysicalPointer;
  352. }
  353. //
  354. // --------------------------------------------------------- Internal Functions
  355. //
  356. KSTATUS
  357. BmpLoadBootConfiguration (
  358. PVOID BootDevice,
  359. PBOOT_CONFIGURATION_CONTEXT Context,
  360. PBOOT_ENTRY *SelectedBootEntry
  361. )
  362. /*++
  363. Routine Description:
  364. This routine loads and read the boot configuration information.
  365. Arguments:
  366. BootDevice - Supplies the open handle to the boot partition.
  367. Context - Supplies a pointer where the initialized boot configuration
  368. context will be returned.
  369. SelectedBootEntry - Supplies a pointer where a pointer to the selected
  370. boot entry will be returned on success.
  371. Return Value:
  372. Status code.
  373. --*/
  374. {
  375. FILE_PROPERTIES DirectoryProperties;
  376. PVOID FileData;
  377. UINTN FileDataSize;
  378. ULONGLONG ModificationDate;
  379. KSTATUS Status;
  380. *SelectedBootEntry = NULL;
  381. FileData = NULL;
  382. Status = BoLookupPath(BootDevice,
  383. NULL,
  384. BOOT_CONFIGURATION_FILE_PATH,
  385. &DirectoryProperties);
  386. if (!KSUCCESS(Status)) {
  387. goto LoadBootConfigurationEnd;
  388. }
  389. Status = BoLoadFile(BootDevice,
  390. &(DirectoryProperties.FileId),
  391. BOOT_CONFIGURATION_FILE_NAME,
  392. &FileData,
  393. &FileDataSize,
  394. &ModificationDate);
  395. if (!KSUCCESS(Status)) {
  396. goto LoadBootConfigurationEnd;
  397. }
  398. //
  399. // Initialize the boot configuration context.
  400. //
  401. RtlZeroMemory(Context, sizeof(BOOT_CONFIGURATION_CONTEXT));
  402. Context->AllocateFunction = BoAllocateMemory;
  403. Context->FreeFunction = BoFreeMemory;
  404. Context->FileData = FileData;
  405. Context->FileDataSize = FileDataSize;
  406. Status = BcInitializeContext(Context);
  407. if (!KSUCCESS(Status)) {
  408. goto LoadBootConfigurationEnd;
  409. }
  410. //
  411. // Read and parse the boot configuration file data.
  412. //
  413. Status = BcReadBootConfigurationFile(Context);
  414. if (!KSUCCESS(Status)) {
  415. goto LoadBootConfigurationEnd;
  416. }
  417. //
  418. // If there's no boot once entry, then fill out the default and return.
  419. //
  420. *SelectedBootEntry = Context->GlobalConfiguration.DefaultBootEntry;
  421. if (Context->GlobalConfiguration.BootOnce == NULL) {
  422. Status = STATUS_SUCCESS;
  423. goto LoadBootConfigurationEnd;
  424. }
  425. //
  426. // There is a boot once entry. Save it as the selected boot entry, then
  427. // work to write out the boot configuration with the boot once field
  428. // cleared.
  429. //
  430. *SelectedBootEntry = Context->GlobalConfiguration.BootOnce;
  431. Context->GlobalConfiguration.BootOnce = NULL;
  432. Status = BcWriteBootConfigurationFile(Context);
  433. if (!KSUCCESS(Status)) {
  434. goto LoadBootConfigurationEnd;
  435. }
  436. Status = BoStoreFile(BootDevice,
  437. DirectoryProperties.FileId,
  438. BOOT_CONFIGURATION_FILE_NAME,
  439. sizeof(BOOT_CONFIGURATION_FILE_NAME),
  440. Context->FileData,
  441. Context->FileDataSize,
  442. ModificationDate);
  443. if (!KSUCCESS(Status)) {
  444. goto LoadBootConfigurationEnd;
  445. }
  446. Status = STATUS_SUCCESS;
  447. LoadBootConfigurationEnd:
  448. if (!KSUCCESS(Status)) {
  449. RtlDebugPrint("Failed to load Boot Configuration: %x.\n", Status);
  450. if (FileData != NULL) {
  451. BoFreeMemory(FileData);
  452. }
  453. }
  454. return Status;
  455. }