WinHost.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176
  1. /**@file
  2. WinNt emulator of pre-SEC phase. It's really a Win32 application, but this is
  3. Ok since all the other modules for NT32 are NOT Win32 applications.
  4. This program gets NT32 PCD setting and figures out what the memory layout
  5. will be, how may FD's will be loaded and also what the boot mode is.
  6. This code produces 128 K of temporary memory for the SEC stack by directly
  7. allocate memory space with ReadWrite and Execute attribute.
  8. Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>
  9. (C) Copyright 2016-2020 Hewlett Packard Enterprise Development LP<BR>
  10. SPDX-License-Identifier: BSD-2-Clause-Patent
  11. **/
  12. #include "WinHost.h"
  13. #ifndef SE_TIME_ZONE_NAME
  14. #define SE_TIME_ZONE_NAME TEXT("SeTimeZonePrivilege")
  15. #endif
  16. //
  17. // The growth size for array of module handle entries
  18. //
  19. #define MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE 0x100
  20. //
  21. // Module handle entry structure
  22. //
  23. typedef struct {
  24. CHAR8 *PdbPointer;
  25. VOID *ModHandle;
  26. } PDB_NAME_TO_MOD_HANDLE;
  27. //
  28. // An Array to hold the module handles
  29. //
  30. PDB_NAME_TO_MOD_HANDLE *mPdbNameModHandleArray = NULL;
  31. UINTN mPdbNameModHandleArraySize = 0;
  32. //
  33. // Default information about where the FD is located.
  34. // This array gets filled in with information from PcdWinNtFirmwareVolume
  35. // The number of array elements is allocated base on parsing
  36. // PcdWinNtFirmwareVolume and the memory is never freed.
  37. //
  38. UINTN gFdInfoCount = 0;
  39. NT_FD_INFO *gFdInfo;
  40. //
  41. // Array that supports separate memory ranges.
  42. // The memory ranges are set by PcdWinNtMemorySizeForSecMain.
  43. // The number of array elements is allocated base on parsing
  44. // PcdWinNtMemorySizeForSecMain value and the memory is never freed.
  45. //
  46. UINTN gSystemMemoryCount = 0;
  47. NT_SYSTEM_MEMORY *gSystemMemory;
  48. BASE_LIBRARY_JUMP_BUFFER mResetJumpBuffer;
  49. CHAR8 *mResetTypeStr[] = {
  50. "EfiResetCold",
  51. "EfiResetWarm",
  52. "EfiResetShutdown",
  53. "EfiResetPlatformSpecific"
  54. };
  55. /*++
  56. Routine Description:
  57. This service is called from Index == 0 until it returns EFI_UNSUPPORTED.
  58. It allows discontinuous memory regions to be supported by the emulator.
  59. It uses gSystemMemory[] and gSystemMemoryCount that were created by
  60. parsing the host environment variable EFI_MEMORY_SIZE.
  61. The size comes from the varaible and the address comes from the call to
  62. UnixOpenFile.
  63. Arguments:
  64. Index - Which memory region to use
  65. MemoryBase - Return Base address of memory region
  66. MemorySize - Return size in bytes of the memory region
  67. Returns:
  68. EFI_SUCCESS - If memory region was mapped
  69. EFI_UNSUPPORTED - If Index is not supported
  70. **/
  71. EFI_STATUS
  72. WinPeiAutoScan (
  73. IN UINTN Index,
  74. OUT EFI_PHYSICAL_ADDRESS *MemoryBase,
  75. OUT UINT64 *MemorySize
  76. )
  77. {
  78. if (Index >= gSystemMemoryCount) {
  79. return EFI_UNSUPPORTED;
  80. }
  81. *MemoryBase = gSystemMemory[Index].Memory;
  82. *MemorySize = gSystemMemory[Index].Size;
  83. return EFI_SUCCESS;
  84. }
  85. /*++
  86. Routine Description:
  87. Return the FD Size and base address. Since the FD is loaded from a
  88. file into host memory only the SEC will know its address.
  89. Arguments:
  90. Index - Which FD, starts at zero.
  91. FdSize - Size of the FD in bytes
  92. FdBase - Start address of the FD. Assume it points to an FV Header
  93. FixUp - Difference between actual FD address and build address
  94. Returns:
  95. EFI_SUCCESS - Return the Base address and size of the FV
  96. EFI_UNSUPPORTED - Index does nto map to an FD in the system
  97. **/
  98. EFI_STATUS
  99. WinFdAddress (
  100. IN UINTN Index,
  101. IN OUT EFI_PHYSICAL_ADDRESS *FdBase,
  102. IN OUT UINT64 *FdSize,
  103. IN OUT EFI_PHYSICAL_ADDRESS *FixUp
  104. )
  105. {
  106. if (Index >= gFdInfoCount) {
  107. return EFI_UNSUPPORTED;
  108. }
  109. *FdBase = (EFI_PHYSICAL_ADDRESS)(UINTN)gFdInfo[Index].Address;
  110. *FdSize = (UINT64)gFdInfo[Index].Size;
  111. *FixUp = 0;
  112. if ((*FdBase == 0) && (*FdSize == 0)) {
  113. return EFI_UNSUPPORTED;
  114. }
  115. if (Index == 0) {
  116. //
  117. // FD 0 has XIP code and well known PCD values
  118. // If the memory buffer could not be allocated at the FD build address
  119. // the Fixup is the difference.
  120. //
  121. *FixUp = *FdBase - PcdGet64 (PcdEmuFdBaseAddress);
  122. }
  123. return EFI_SUCCESS;
  124. }
  125. /*++
  126. Routine Description:
  127. Since the SEC is the only Unix program in stack it must export
  128. an interface to do POSIX calls. gUnix is initialized in UnixThunk.c.
  129. Arguments:
  130. InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
  131. InterfaceBase - Address of the gUnix global
  132. Returns:
  133. EFI_SUCCESS - Data returned
  134. **/
  135. VOID *
  136. WinThunk (
  137. VOID
  138. )
  139. {
  140. return &gEmuThunkProtocol;
  141. }
  142. EMU_THUNK_PPI mSecEmuThunkPpi = {
  143. WinPeiAutoScan,
  144. WinFdAddress,
  145. WinThunk
  146. };
  147. VOID
  148. SecPrint (
  149. CHAR8 *Format,
  150. ...
  151. )
  152. {
  153. va_list Marker;
  154. UINTN CharCount;
  155. CHAR8 Buffer[0x1000];
  156. va_start (Marker, Format);
  157. _vsnprintf (Buffer, sizeof (Buffer), Format, Marker);
  158. va_end (Marker);
  159. CharCount = strlen (Buffer);
  160. WriteFile (
  161. GetStdHandle (STD_OUTPUT_HANDLE),
  162. Buffer,
  163. (DWORD)CharCount,
  164. (LPDWORD)&CharCount,
  165. NULL
  166. );
  167. }
  168. /**
  169. Resets the entire platform.
  170. @param[in] ResetType The type of reset to perform.
  171. @param[in] ResetStatus The status code for the reset.
  172. @param[in] DataSize The size, in bytes, of ResetData.
  173. @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or EfiResetShutdown
  174. the data buffer starts with a Null-terminated string, optionally
  175. followed by additional binary data. The string is a description
  176. that the caller may use to further indicate the reason for the
  177. system reset.
  178. **/
  179. VOID
  180. EFIAPI
  181. WinReset (
  182. IN EFI_RESET_TYPE ResetType,
  183. IN EFI_STATUS ResetStatus,
  184. IN UINTN DataSize,
  185. IN VOID *ResetData OPTIONAL
  186. )
  187. {
  188. UINTN Index;
  189. ASSERT (ResetType <= EfiResetPlatformSpecific);
  190. SecPrint (" Emu ResetSystem is called: ResetType = %s\n", mResetTypeStr[ResetType]);
  191. if (ResetType == EfiResetShutdown) {
  192. exit (0);
  193. } else {
  194. //
  195. // Unload all DLLs
  196. //
  197. for (Index = 0; Index < mPdbNameModHandleArraySize; Index++) {
  198. if (mPdbNameModHandleArray[Index].PdbPointer != NULL) {
  199. SecPrint (" Emu Unload DLL: %s\n", mPdbNameModHandleArray[Index].PdbPointer);
  200. FreeLibrary (mPdbNameModHandleArray[Index].ModHandle);
  201. HeapFree (GetProcessHeap (), 0, mPdbNameModHandleArray[Index].PdbPointer);
  202. mPdbNameModHandleArray[Index].PdbPointer = NULL;
  203. }
  204. }
  205. //
  206. // Jump back to SetJump with jump code = ResetType + 1
  207. //
  208. LongJump (&mResetJumpBuffer, ResetType + 1);
  209. }
  210. }
  211. EFI_PEI_RESET2_PPI mEmuReset2Ppi = {
  212. WinReset
  213. };
  214. /*++
  215. Routine Description:
  216. Check to see if an address range is in the EFI GCD memory map.
  217. This is all of GCD for system memory passed to DXE Core. FV
  218. mapping and other device mapped into system memory are not
  219. inlcuded in the check.
  220. Arguments:
  221. Index - Which memory region to use
  222. MemoryBase - Return Base address of memory region
  223. MemorySize - Return size in bytes of the memory region
  224. Returns:
  225. TRUE - Address is in the EFI GCD memory map
  226. FALSE - Address is NOT in memory map
  227. **/
  228. BOOLEAN
  229. EfiSystemMemoryRange (
  230. IN VOID *MemoryAddress
  231. )
  232. {
  233. UINTN Index;
  234. EFI_PHYSICAL_ADDRESS MemoryBase;
  235. MemoryBase = (EFI_PHYSICAL_ADDRESS)(UINTN)MemoryAddress;
  236. for (Index = 0; Index < gSystemMemoryCount; Index++) {
  237. if ((MemoryBase >= gSystemMemory[Index].Memory) &&
  238. (MemoryBase < (gSystemMemory[Index].Memory + gSystemMemory[Index].Size)))
  239. {
  240. return TRUE;
  241. }
  242. }
  243. return FALSE;
  244. }
  245. EFI_STATUS
  246. WinNtOpenFile (
  247. IN CHAR16 *FileName OPTIONAL,
  248. IN UINT32 MapSize,
  249. IN DWORD CreationDisposition,
  250. IN OUT VOID **BaseAddress,
  251. OUT UINTN *Length
  252. )
  253. /*++
  254. Routine Description:
  255. Opens and memory maps a file using WinNt services. If *BaseAddress is non zero
  256. the process will try and allocate the memory starting at BaseAddress.
  257. Arguments:
  258. FileName - The name of the file to open and map
  259. MapSize - The amount of the file to map in bytes
  260. CreationDisposition - The flags to pass to CreateFile(). Use to create new files for
  261. memory emulation, and exiting files for firmware volume emulation
  262. BaseAddress - The base address of the mapped file in the user address space.
  263. If *BaseAddress is 0, the new memory region is used.
  264. If *BaseAddress is not 0, the request memory region is used for
  265. the mapping of the file into the process space.
  266. Length - The size of the mapped region in bytes
  267. Returns:
  268. EFI_SUCCESS - The file was opened and mapped.
  269. EFI_NOT_FOUND - FileName was not found in the current directory
  270. EFI_DEVICE_ERROR - An error occurred attempting to map the opened file
  271. --*/
  272. {
  273. HANDLE NtFileHandle;
  274. HANDLE NtMapHandle;
  275. VOID *VirtualAddress;
  276. UINTN FileSize;
  277. //
  278. // Use Win API to open/create a file
  279. //
  280. NtFileHandle = INVALID_HANDLE_VALUE;
  281. if (FileName != NULL) {
  282. NtFileHandle = CreateFile (
  283. FileName,
  284. GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE,
  285. FILE_SHARE_READ,
  286. NULL,
  287. CreationDisposition,
  288. FILE_ATTRIBUTE_NORMAL,
  289. NULL
  290. );
  291. if (NtFileHandle == INVALID_HANDLE_VALUE) {
  292. return EFI_NOT_FOUND;
  293. }
  294. }
  295. //
  296. // Map the open file into a memory range
  297. //
  298. NtMapHandle = CreateFileMapping (
  299. NtFileHandle,
  300. NULL,
  301. PAGE_EXECUTE_READWRITE,
  302. 0,
  303. MapSize,
  304. NULL
  305. );
  306. if (NtMapHandle == NULL) {
  307. return EFI_DEVICE_ERROR;
  308. }
  309. //
  310. // Get the virtual address (address in the emulator) of the mapped file
  311. //
  312. VirtualAddress = MapViewOfFileEx (
  313. NtMapHandle,
  314. FILE_MAP_EXECUTE | FILE_MAP_ALL_ACCESS,
  315. 0,
  316. 0,
  317. MapSize,
  318. *BaseAddress
  319. );
  320. if (VirtualAddress == NULL) {
  321. return EFI_DEVICE_ERROR;
  322. }
  323. if (MapSize == 0) {
  324. //
  325. // Seek to the end of the file to figure out the true file size.
  326. //
  327. FileSize = SetFilePointer (
  328. NtFileHandle,
  329. 0,
  330. NULL,
  331. FILE_END
  332. );
  333. if (FileSize == -1) {
  334. return EFI_DEVICE_ERROR;
  335. }
  336. *Length = FileSize;
  337. } else {
  338. *Length = MapSize;
  339. }
  340. *BaseAddress = VirtualAddress;
  341. return EFI_SUCCESS;
  342. }
  343. INTN
  344. EFIAPI
  345. main (
  346. IN INT Argc,
  347. IN CHAR8 **Argv,
  348. IN CHAR8 **Envp
  349. )
  350. /*++
  351. Routine Description:
  352. Main entry point to SEC for WinNt. This is a Windows program
  353. Arguments:
  354. Argc - Number of command line arguments
  355. Argv - Array of command line argument strings
  356. Envp - Array of environment variable strings
  357. Returns:
  358. 0 - Normal exit
  359. 1 - Abnormal exit
  360. --*/
  361. {
  362. EFI_STATUS Status;
  363. HANDLE Token;
  364. TOKEN_PRIVILEGES TokenPrivileges;
  365. VOID *TemporaryRam;
  366. UINT32 TemporaryRamSize;
  367. VOID *EmuMagicPage;
  368. UINTN Index;
  369. UINTN Index1;
  370. CHAR16 *FileName;
  371. CHAR16 *FileNamePtr;
  372. BOOLEAN Done;
  373. EFI_PEI_FILE_HANDLE FileHandle;
  374. VOID *SecFile;
  375. CHAR16 *MemorySizeStr;
  376. CHAR16 *FirmwareVolumesStr;
  377. UINTN ProcessAffinityMask;
  378. UINTN SystemAffinityMask;
  379. INT32 LowBit;
  380. UINTN ResetJumpCode;
  381. EMU_THUNK_PPI *SecEmuThunkPpi;
  382. //
  383. // Enable the privilege so that RTC driver can successfully run SetTime()
  384. //
  385. OpenProcessToken (GetCurrentProcess (), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &Token);
  386. if (LookupPrivilegeValue (NULL, SE_TIME_ZONE_NAME, &TokenPrivileges.Privileges[0].Luid)) {
  387. TokenPrivileges.PrivilegeCount = 1;
  388. TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  389. AdjustTokenPrivileges (Token, FALSE, &TokenPrivileges, 0, (PTOKEN_PRIVILEGES)NULL, 0);
  390. }
  391. MemorySizeStr = (CHAR16 *)PcdGetPtr (PcdEmuMemorySize);
  392. FirmwareVolumesStr = (CHAR16 *)PcdGetPtr (PcdEmuFirmwareVolume);
  393. SecPrint ("\n\rEDK II WIN Host Emulation Environment from http://www.tianocore.org/edk2/\n\r");
  394. //
  395. // Determine the first thread available to this process.
  396. //
  397. if (GetProcessAffinityMask (GetCurrentProcess (), &ProcessAffinityMask, &SystemAffinityMask)) {
  398. LowBit = (INT32)LowBitSet32 ((UINT32)ProcessAffinityMask);
  399. if (LowBit != -1) {
  400. //
  401. // Force the system to bind the process to a single thread to work
  402. // around odd semaphore type crashes.
  403. //
  404. SetProcessAffinityMask (GetCurrentProcess (), (INTN)(BIT0 << LowBit));
  405. }
  406. }
  407. //
  408. // Make some Windows calls to Set the process to the highest priority in the
  409. // idle class. We need this to have good performance.
  410. //
  411. SetPriorityClass (GetCurrentProcess (), IDLE_PRIORITY_CLASS);
  412. SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST);
  413. SecInitializeThunk ();
  414. //
  415. // PPIs pased into PEI_CORE
  416. //
  417. SecEmuThunkPpi = AllocateZeroPool (sizeof (EMU_THUNK_PPI) + FixedPcdGet32 (PcdPersistentMemorySize));
  418. if (SecEmuThunkPpi == NULL) {
  419. SecPrint ("ERROR : Can not allocate memory for SecEmuThunkPpi. Exiting.\n");
  420. exit (1);
  421. }
  422. CopyMem (SecEmuThunkPpi, &mSecEmuThunkPpi, sizeof (EMU_THUNK_PPI));
  423. SecEmuThunkPpi->PersistentMemorySize = FixedPcdGet32 (PcdPersistentMemorySize);
  424. AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEmuThunkPpiGuid, SecEmuThunkPpi);
  425. AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiPeiReset2PpiGuid, &mEmuReset2Ppi);
  426. //
  427. // Emulator Bus Driver Thunks
  428. //
  429. AddThunkProtocol (&mWinNtWndThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuGop), TRUE);
  430. AddThunkProtocol (&mWinNtFileSystemThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuFileSystem), TRUE);
  431. AddThunkProtocol (&mWinNtBlockIoThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuVirtualDisk), TRUE);
  432. AddThunkProtocol (&mWinNtSnpThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuNetworkInterface), TRUE);
  433. //
  434. // Allocate space for gSystemMemory Array
  435. //
  436. gSystemMemoryCount = CountSeparatorsInString (MemorySizeStr, '!') + 1;
  437. gSystemMemory = calloc (gSystemMemoryCount, sizeof (NT_SYSTEM_MEMORY));
  438. if (gSystemMemory == NULL) {
  439. SecPrint ("ERROR : Can not allocate memory for %S. Exiting.\n\r", MemorySizeStr);
  440. exit (1);
  441. }
  442. //
  443. // Allocate "physical" memory space for emulator. It will be reported out later throuth MemoryAutoScan()
  444. //
  445. for (Index = 0, Done = FALSE; !Done; Index++) {
  446. ASSERT (Index < gSystemMemoryCount);
  447. gSystemMemory[Index].Size = ((UINT64)_wtoi (MemorySizeStr)) * ((UINT64)SIZE_1MB);
  448. gSystemMemory[Index].Memory = (EFI_PHYSICAL_ADDRESS)(UINTN)VirtualAlloc (NULL, (SIZE_T)(gSystemMemory[Index].Size), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  449. if (gSystemMemory[Index].Memory == 0) {
  450. return EFI_OUT_OF_RESOURCES;
  451. }
  452. //
  453. // Find the next region
  454. //
  455. for (Index1 = 0; MemorySizeStr[Index1] != '!' && MemorySizeStr[Index1] != 0; Index1++) {
  456. }
  457. if (MemorySizeStr[Index1] == 0) {
  458. Done = TRUE;
  459. }
  460. MemorySizeStr = MemorySizeStr + Index1 + 1;
  461. }
  462. //
  463. // Allocate space for gSystemMemory Array
  464. //
  465. gFdInfoCount = CountSeparatorsInString (FirmwareVolumesStr, '!') + 1;
  466. gFdInfo = calloc (gFdInfoCount, sizeof (NT_FD_INFO));
  467. if (gFdInfo == NULL) {
  468. SecPrint ("ERROR : Can not allocate memory for %S. Exiting.\n\r", FirmwareVolumesStr);
  469. exit (1);
  470. }
  471. //
  472. // Setup Boot Mode.
  473. //
  474. SecPrint (" BootMode 0x%02x\n\r", PcdGet32 (PcdEmuBootMode));
  475. //
  476. // Allocate 128K memory to emulate temp memory for PEI.
  477. // on a real platform this would be SRAM, or using the cache as RAM.
  478. // Set TemporaryRam to zero so WinNtOpenFile will allocate a new mapping
  479. //
  480. TemporaryRamSize = TEMPORARY_RAM_SIZE;
  481. TemporaryRam = VirtualAlloc (NULL, (SIZE_T)(TemporaryRamSize), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  482. if (TemporaryRam == NULL) {
  483. SecPrint ("ERROR : Can not allocate enough space for SecStack\n\r");
  484. exit (1);
  485. }
  486. //
  487. // If enabled use the magic page to communicate between modules
  488. // This replaces the PI PeiServicesTable pointer mechanism that
  489. // deos not work in the emulator. It also allows the removal of
  490. // writable globals from SEC, PEI_CORE (libraries), PEIMs
  491. //
  492. EmuMagicPage = (VOID *)(UINTN)(FixedPcdGet64 (PcdPeiServicesTablePage) & MAX_UINTN);
  493. if (EmuMagicPage != NULL) {
  494. UINT64 Size;
  495. Status = WinNtOpenFile (
  496. NULL,
  497. SIZE_4KB,
  498. 0,
  499. &EmuMagicPage,
  500. &Size
  501. );
  502. if (EFI_ERROR (Status)) {
  503. SecPrint ("ERROR : Could not allocate PeiServicesTablePage @ %p\n\r", EmuMagicPage);
  504. return EFI_DEVICE_ERROR;
  505. }
  506. }
  507. //
  508. // Open All the firmware volumes and remember the info in the gFdInfo global
  509. // Meanwhile, find the SEC Core.
  510. //
  511. FileNamePtr = AllocateCopyPool (StrSize (FirmwareVolumesStr), FirmwareVolumesStr);
  512. if (FileNamePtr == NULL) {
  513. SecPrint ("ERROR : Can not allocate memory for firmware volume string\n\r");
  514. exit (1);
  515. }
  516. for (Done = FALSE, Index = 0, SecFile = NULL; !Done; Index++) {
  517. FileName = FileNamePtr;
  518. for (Index1 = 0; (FileNamePtr[Index1] != '!') && (FileNamePtr[Index1] != 0); Index1++) {
  519. }
  520. if (FileNamePtr[Index1] == 0) {
  521. Done = TRUE;
  522. } else {
  523. FileNamePtr[Index1] = '\0';
  524. FileNamePtr = &FileNamePtr[Index1 + 1];
  525. }
  526. //
  527. // Open the FD and remember where it got mapped into our processes address space
  528. //
  529. Status = WinNtOpenFile (
  530. FileName,
  531. 0,
  532. OPEN_EXISTING,
  533. &gFdInfo[Index].Address,
  534. &gFdInfo[Index].Size
  535. );
  536. if (EFI_ERROR (Status)) {
  537. SecPrint ("ERROR : Can not open Firmware Device File %S (0x%X). Exiting.\n\r", FileName, Status);
  538. exit (1);
  539. }
  540. SecPrint (" FD loaded from %S", FileName);
  541. if (SecFile == NULL) {
  542. //
  543. // Assume the beginning of the FD is an FV and look for the SEC Core.
  544. // Load the first one we find.
  545. //
  546. FileHandle = NULL;
  547. Status = PeiServicesFfsFindNextFile (
  548. EFI_FV_FILETYPE_SECURITY_CORE,
  549. (EFI_PEI_FV_HANDLE)gFdInfo[Index].Address,
  550. &FileHandle
  551. );
  552. if (!EFI_ERROR (Status)) {
  553. Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, &SecFile);
  554. if (!EFI_ERROR (Status)) {
  555. SecPrint (" contains SEC Core");
  556. }
  557. }
  558. }
  559. SecPrint ("\n\r");
  560. }
  561. ResetJumpCode = SetJump (&mResetJumpBuffer);
  562. //
  563. // Do not clear memory content for warm reset.
  564. //
  565. if (ResetJumpCode != EfiResetWarm + 1) {
  566. SecPrint (" OS Emulator clearing temp RAM and physical RAM (to be discovered later)......\n\r");
  567. SetMem32 (TemporaryRam, TemporaryRamSize, PcdGet32 (PcdInitValueInTempStack));
  568. for (Index = 0; Index < gSystemMemoryCount; Index++) {
  569. SetMem32 ((VOID *)(UINTN)gSystemMemory[Index].Memory, (UINTN)gSystemMemory[Index].Size, PcdGet32 (PcdInitValueInTempStack));
  570. }
  571. }
  572. SecPrint (
  573. " OS Emulator passing in %u KB of temp RAM at 0x%08lx to SEC\n\r",
  574. TemporaryRamSize / SIZE_1KB,
  575. TemporaryRam
  576. );
  577. //
  578. // Hand off to SEC Core
  579. //
  580. SecLoadSecCore ((UINTN)TemporaryRam, TemporaryRamSize, gFdInfo[0].Address, gFdInfo[0].Size, SecFile);
  581. //
  582. // If we get here, then the SEC Core returned. This is an error as SEC should
  583. // always hand off to PEI Core and then on to DXE Core.
  584. //
  585. SecPrint ("ERROR : SEC returned\n\r");
  586. exit (1);
  587. }
  588. VOID
  589. SecLoadSecCore (
  590. IN UINTN TemporaryRam,
  591. IN UINTN TemporaryRamSize,
  592. IN VOID *BootFirmwareVolumeBase,
  593. IN UINTN BootFirmwareVolumeSize,
  594. IN VOID *SecCorePe32File
  595. )
  596. /*++
  597. Routine Description:
  598. This is the service to load the SEC Core from the Firmware Volume
  599. Arguments:
  600. TemporaryRam - Memory to use for SEC.
  601. TemporaryRamSize - Size of Memory to use for SEC
  602. BootFirmwareVolumeBase - Start of the Boot FV
  603. SecCorePe32File - SEC Core PE32
  604. Returns:
  605. Success means control is transferred and thus we should never return
  606. --*/
  607. {
  608. EFI_STATUS Status;
  609. VOID *TopOfStack;
  610. VOID *SecCoreEntryPoint;
  611. EFI_SEC_PEI_HAND_OFF *SecCoreData;
  612. UINTN SecStackSize;
  613. //
  614. // Compute Top Of Memory for Stack and PEI Core Allocations
  615. //
  616. SecStackSize = TemporaryRamSize >> 1;
  617. //
  618. // |-----------| <---- TemporaryRamBase + TemporaryRamSize
  619. // | Heap |
  620. // | |
  621. // |-----------| <---- StackBase / PeiTemporaryMemoryBase
  622. // | |
  623. // | Stack |
  624. // |-----------| <---- TemporaryRamBase
  625. //
  626. TopOfStack = (VOID *)(TemporaryRam + SecStackSize);
  627. //
  628. // Reservet space for storing PeiCore's parament in stack.
  629. //
  630. TopOfStack = (VOID *)((UINTN)TopOfStack - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT);
  631. TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
  632. //
  633. // Bind this information into the SEC hand-off state
  634. //
  635. SecCoreData = (EFI_SEC_PEI_HAND_OFF *)(UINTN)TopOfStack;
  636. SecCoreData->DataSize = sizeof (EFI_SEC_PEI_HAND_OFF);
  637. SecCoreData->BootFirmwareVolumeBase = BootFirmwareVolumeBase;
  638. SecCoreData->BootFirmwareVolumeSize = BootFirmwareVolumeSize;
  639. SecCoreData->TemporaryRamBase = (VOID *)TemporaryRam;
  640. SecCoreData->TemporaryRamSize = TemporaryRamSize;
  641. SecCoreData->StackBase = SecCoreData->TemporaryRamBase;
  642. SecCoreData->StackSize = SecStackSize;
  643. SecCoreData->PeiTemporaryRamBase = (VOID *)((UINTN)SecCoreData->TemporaryRamBase + SecStackSize);
  644. SecCoreData->PeiTemporaryRamSize = TemporaryRamSize - SecStackSize;
  645. //
  646. // Load the PEI Core from a Firmware Volume
  647. //
  648. Status = SecPeCoffGetEntryPoint (
  649. SecCorePe32File,
  650. &SecCoreEntryPoint
  651. );
  652. if (EFI_ERROR (Status)) {
  653. return;
  654. }
  655. //
  656. // Transfer control to the SEC Core
  657. //
  658. SwitchStack (
  659. (SWITCH_STACK_ENTRY_POINT)(UINTN)SecCoreEntryPoint,
  660. SecCoreData,
  661. GetThunkPpiList (),
  662. TopOfStack
  663. );
  664. //
  665. // If we get here, then the SEC Core returned. This is an error
  666. //
  667. return;
  668. }
  669. RETURN_STATUS
  670. EFIAPI
  671. SecPeCoffGetEntryPoint (
  672. IN VOID *Pe32Data,
  673. IN OUT VOID **EntryPoint
  674. )
  675. {
  676. EFI_STATUS Status;
  677. PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
  678. ZeroMem (&ImageContext, sizeof (ImageContext));
  679. ImageContext.Handle = Pe32Data;
  680. ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)SecImageRead;
  681. Status = PeCoffLoaderGetImageInfo (&ImageContext);
  682. if (EFI_ERROR (Status)) {
  683. return Status;
  684. }
  685. //
  686. // XIP for SEC and PEI_CORE
  687. //
  688. ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data;
  689. Status = PeCoffLoaderLoadImage (&ImageContext);
  690. if (EFI_ERROR (Status)) {
  691. return Status;
  692. }
  693. Status = PeCoffLoaderRelocateImage (&ImageContext);
  694. if (EFI_ERROR (Status)) {
  695. return Status;
  696. }
  697. *EntryPoint = (VOID *)(UINTN)ImageContext.EntryPoint;
  698. return EFI_SUCCESS;
  699. }
  700. EFI_STATUS
  701. EFIAPI
  702. SecImageRead (
  703. IN VOID *FileHandle,
  704. IN UINTN FileOffset,
  705. IN OUT UINTN *ReadSize,
  706. OUT VOID *Buffer
  707. )
  708. /*++
  709. Routine Description:
  710. Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
  711. Arguments:
  712. FileHandle - The handle to the PE/COFF file
  713. FileOffset - The offset, in bytes, into the file to read
  714. ReadSize - The number of bytes to read from the file starting at FileOffset
  715. Buffer - A pointer to the buffer to read the data into.
  716. Returns:
  717. EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
  718. --*/
  719. {
  720. CHAR8 *Destination8;
  721. CHAR8 *Source8;
  722. UINTN Length;
  723. Destination8 = Buffer;
  724. Source8 = (CHAR8 *)((UINTN)FileHandle + FileOffset);
  725. Length = *ReadSize;
  726. while (Length--) {
  727. *(Destination8++) = *(Source8++);
  728. }
  729. return EFI_SUCCESS;
  730. }
  731. CHAR16 *
  732. AsciiToUnicode (
  733. IN CHAR8 *Ascii,
  734. IN UINTN *StrLen OPTIONAL
  735. )
  736. /*++
  737. Routine Description:
  738. Convert the passed in Ascii string to Unicode.
  739. Optionally return the length of the strings.
  740. Arguments:
  741. Ascii - Ascii string to convert
  742. StrLen - Length of string
  743. Returns:
  744. Pointer to malloc'ed Unicode version of Ascii
  745. --*/
  746. {
  747. UINTN Index;
  748. CHAR16 *Unicode;
  749. //
  750. // Allocate a buffer for unicode string
  751. //
  752. for (Index = 0; Ascii[Index] != '\0'; Index++) {
  753. }
  754. Unicode = malloc ((Index + 1) * sizeof (CHAR16));
  755. if (Unicode == NULL) {
  756. return NULL;
  757. }
  758. for (Index = 0; Ascii[Index] != '\0'; Index++) {
  759. Unicode[Index] = (CHAR16)Ascii[Index];
  760. }
  761. Unicode[Index] = '\0';
  762. if (StrLen != NULL) {
  763. *StrLen = Index;
  764. }
  765. return Unicode;
  766. }
  767. UINTN
  768. CountSeparatorsInString (
  769. IN CONST CHAR16 *String,
  770. IN CHAR16 Separator
  771. )
  772. /*++
  773. Routine Description:
  774. Count the number of separators in String
  775. Arguments:
  776. String - String to process
  777. Separator - Item to count
  778. Returns:
  779. Number of Separator in String
  780. --*/
  781. {
  782. UINTN Count;
  783. for (Count = 0; *String != '\0'; String++) {
  784. if (*String == Separator) {
  785. Count++;
  786. }
  787. }
  788. return Count;
  789. }
  790. /**
  791. Store the ModHandle in an array indexed by the Pdb File name.
  792. The ModHandle is needed to unload the image.
  793. @param ImageContext - Input data returned from PE Laoder Library. Used to find the
  794. .PDB file name of the PE Image.
  795. @param ModHandle - Returned from LoadLibraryEx() and stored for call to
  796. FreeLibrary().
  797. @return return EFI_SUCCESS when ModHandle was stored.
  798. --*/
  799. EFI_STATUS
  800. AddModHandle (
  801. IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
  802. IN VOID *ModHandle
  803. )
  804. {
  805. UINTN Index;
  806. PDB_NAME_TO_MOD_HANDLE *Array;
  807. UINTN PreviousSize;
  808. PDB_NAME_TO_MOD_HANDLE *TempArray;
  809. HANDLE Handle;
  810. UINTN Size;
  811. //
  812. // Return EFI_ALREADY_STARTED if this DLL has already been loaded
  813. //
  814. Array = mPdbNameModHandleArray;
  815. for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {
  816. if ((Array->PdbPointer != NULL) && (Array->ModHandle == ModHandle)) {
  817. return EFI_ALREADY_STARTED;
  818. }
  819. }
  820. Array = mPdbNameModHandleArray;
  821. for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {
  822. if (Array->PdbPointer == NULL) {
  823. //
  824. // Make a copy of the stirng and store the ModHandle
  825. //
  826. Handle = GetProcessHeap ();
  827. Size = AsciiStrLen (ImageContext->PdbPointer) + 1;
  828. Array->PdbPointer = HeapAlloc (Handle, HEAP_ZERO_MEMORY, Size);
  829. ASSERT (Array->PdbPointer != NULL);
  830. AsciiStrCpyS (Array->PdbPointer, Size, ImageContext->PdbPointer);
  831. Array->ModHandle = ModHandle;
  832. return EFI_SUCCESS;
  833. }
  834. }
  835. //
  836. // No free space in mPdbNameModHandleArray so grow it by
  837. // MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE entires.
  838. //
  839. PreviousSize = mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE);
  840. mPdbNameModHandleArraySize += MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE;
  841. //
  842. // re-allocate a new buffer and copy the old values to the new locaiton.
  843. //
  844. TempArray = HeapAlloc (
  845. GetProcessHeap (),
  846. HEAP_ZERO_MEMORY,
  847. mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE)
  848. );
  849. CopyMem ((VOID *)(UINTN)TempArray, (VOID *)(UINTN)mPdbNameModHandleArray, PreviousSize);
  850. HeapFree (GetProcessHeap (), 0, mPdbNameModHandleArray);
  851. mPdbNameModHandleArray = TempArray;
  852. if (mPdbNameModHandleArray == NULL) {
  853. ASSERT (FALSE);
  854. return EFI_OUT_OF_RESOURCES;
  855. }
  856. return AddModHandle (ImageContext, ModHandle);
  857. }
  858. /**
  859. Return the ModHandle and delete the entry in the array.
  860. @param ImageContext - Input data returned from PE Laoder Library. Used to find the
  861. .PDB file name of the PE Image.
  862. @return
  863. ModHandle - ModHandle assoicated with ImageContext is returned
  864. NULL - No ModHandle associated with ImageContext
  865. **/
  866. VOID *
  867. RemoveModHandle (
  868. IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
  869. )
  870. {
  871. UINTN Index;
  872. PDB_NAME_TO_MOD_HANDLE *Array;
  873. if (ImageContext->PdbPointer == NULL) {
  874. //
  875. // If no PDB pointer there is no ModHandle so return NULL
  876. //
  877. return NULL;
  878. }
  879. Array = mPdbNameModHandleArray;
  880. for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {
  881. if ((Array->PdbPointer != NULL) && (AsciiStrCmp (Array->PdbPointer, ImageContext->PdbPointer) == 0)) {
  882. //
  883. // If you find a match return it and delete the entry
  884. //
  885. HeapFree (GetProcessHeap (), 0, Array->PdbPointer);
  886. Array->PdbPointer = NULL;
  887. return Array->ModHandle;
  888. }
  889. }
  890. return NULL;
  891. }
  892. VOID
  893. EFIAPI
  894. PeCoffLoaderRelocateImageExtraAction (
  895. IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
  896. )
  897. {
  898. EFI_STATUS Status;
  899. VOID *DllEntryPoint;
  900. CHAR16 *DllFileName;
  901. HMODULE Library;
  902. UINTN Index;
  903. ASSERT (ImageContext != NULL);
  904. //
  905. // If we load our own PE COFF images the Windows debugger can not source
  906. // level debug our code. If a valid PDB pointer exists use it to load
  907. // the *.dll file as a library using Windows* APIs. This allows
  908. // source level debug. The image is still loaded and relocated
  909. // in the Framework memory space like on a real system (by the code above),
  910. // but the entry point points into the DLL loaded by the code below.
  911. //
  912. DllEntryPoint = NULL;
  913. //
  914. // Load the DLL if it's not an EBC image.
  915. //
  916. if ((ImageContext->PdbPointer != NULL) &&
  917. (ImageContext->Machine != EFI_IMAGE_MACHINE_EBC))
  918. {
  919. //
  920. // Convert filename from ASCII to Unicode
  921. //
  922. DllFileName = AsciiToUnicode (ImageContext->PdbPointer, &Index);
  923. //
  924. // Check that we have a valid filename
  925. //
  926. if ((Index < 5) || (DllFileName[Index - 4] != '.')) {
  927. free (DllFileName);
  928. //
  929. // Never return an error if PeCoffLoaderRelocateImage() succeeded.
  930. // The image will run, but we just can't source level debug. If we
  931. // return an error the image will not run.
  932. //
  933. return;
  934. }
  935. //
  936. // Replace .PDB with .DLL on the filename
  937. //
  938. DllFileName[Index - 3] = 'D';
  939. DllFileName[Index - 2] = 'L';
  940. DllFileName[Index - 1] = 'L';
  941. //
  942. // Load the .DLL file into the user process's address space for source
  943. // level debug
  944. //
  945. Library = LoadLibraryEx (DllFileName, NULL, DONT_RESOLVE_DLL_REFERENCES);
  946. if (Library != NULL) {
  947. //
  948. // InitializeDriver is the entry point we put in all our EFI DLL's. The
  949. // DONT_RESOLVE_DLL_REFERENCES argument to LoadLIbraryEx() suppresses the
  950. // normal DLL entry point of DllMain, and prevents other modules that are
  951. // referenced in side the DllFileName from being loaded. There is no error
  952. // checking as the we can point to the PE32 image loaded by Tiano. This
  953. // step is only needed for source level debugging
  954. //
  955. DllEntryPoint = (VOID *)(UINTN)GetProcAddress (Library, "InitializeDriver");
  956. }
  957. if ((Library != NULL) && (DllEntryPoint != NULL)) {
  958. Status = AddModHandle (ImageContext, Library);
  959. if (Status == EFI_ALREADY_STARTED) {
  960. //
  961. // If the DLL has already been loaded before, then this instance of the DLL can not be debugged.
  962. //
  963. ImageContext->PdbPointer = NULL;
  964. SecPrint ("WARNING: DLL already loaded. No source level debug %S.\n\r", DllFileName);
  965. } else {
  966. //
  967. // This DLL is not already loaded, so source level debugging is supported.
  968. //
  969. ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)DllEntryPoint;
  970. SecPrint ("LoadLibraryEx (\n\r %S,\n\r NULL, DONT_RESOLVE_DLL_REFERENCES)\n\r", DllFileName);
  971. }
  972. } else {
  973. SecPrint ("WARNING: No source level debug %S. \n\r", DllFileName);
  974. }
  975. free (DllFileName);
  976. }
  977. }
  978. VOID
  979. EFIAPI
  980. PeCoffLoaderUnloadImageExtraAction (
  981. IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
  982. )
  983. {
  984. VOID *ModHandle;
  985. ASSERT (ImageContext != NULL);
  986. ModHandle = RemoveModHandle (ImageContext);
  987. if (ModHandle != NULL) {
  988. FreeLibrary (ModHandle);
  989. SecPrint ("FreeLibrary (\n\r %s)\n\r", ImageContext->PdbPointer);
  990. } else {
  991. SecPrint ("WARNING: Unload image without source level debug\n\r");
  992. }
  993. }
  994. VOID
  995. _ModuleEntryPoint (
  996. VOID
  997. )
  998. {
  999. }