Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

681 lines
15 KiB

  1. #include <efi.h>
  2. #include <efilib.h>
  3. #define MAX_ENV_SIZE 1024
  4. #define MAXUSHORT (0xFFFF)
  5. //
  6. // Globals for stdout
  7. //
  8. SIMPLE_TEXT_OUTPUT_INTERFACE *ConOut;
  9. SIMPLE_INPUT_INTERFACE *ConIn;
  10. //
  11. // Globals for protocol handler
  12. //
  13. EFI_HANDLE_PROTOCOL HandleProtocol;
  14. EFI_LOCATE_HANDLE LocateHandle;
  15. EFI_LOCATE_DEVICE_PATH LocateDevicePath;
  16. EFI_IMAGE_LOAD LoadImage;
  17. EFI_IMAGE_START StartImage;
  18. EFI_SET_VARIABLE SetVariable;
  19. EFI_HANDLE MenuImageHandle;
  20. EFI_LOADED_IMAGE *ExeImage;
  21. //
  22. // globals for managing boot entries
  23. //
  24. UINT32 NvrAttributes;
  25. UINTN NvrOrderCount;
  26. UINT16 *NvrOrder;
  27. //
  28. // prototypes
  29. //
  30. UINT32 GetInputKey();
  31. void DisplayKey(UINT32);
  32. EFI_STATUS
  33. OpenCreateFile (
  34. UINT64 OCFlags,
  35. EFI_FILE_HANDLE* StartHdl,
  36. CHAR16* Name
  37. );
  38. EFI_STATUS
  39. InsertBootOption(
  40. VOID *BootOption,
  41. UINT64 BootOptionSize
  42. );
  43. INTN
  44. ParseNvrFile (
  45. EFI_FILE_HANDLE NvrFile
  46. );
  47. EFI_STATUS
  48. FindFreeBootOption(
  49. CHAR16 *FreeIdx
  50. );
  51. INTN
  52. RestoreNvr (
  53. CHAR16* fileName
  54. );
  55. VOID
  56. InitializeStdOut(
  57. IN struct _EFI_SYSTEM_TABLE *SystemTable
  58. )
  59. {
  60. //
  61. // Stash some of the efi stdout pointers
  62. //
  63. ConOut = SystemTable->ConOut;
  64. ConIn = SystemTable->ConIn;
  65. }
  66. //
  67. //
  68. //
  69. void
  70. InitializeProtocols(
  71. IN struct _EFI_SYSTEM_TABLE *SystemTable
  72. )
  73. {
  74. EFI_BOOT_SERVICES *bootServices;
  75. EFI_RUNTIME_SERVICES *runtimeServices;
  76. //
  77. // Stash some of the handle protocol pointers
  78. //
  79. bootServices = SystemTable->BootServices;
  80. HandleProtocol = bootServices->HandleProtocol;
  81. LocateHandle = bootServices->LocateHandle;
  82. LocateDevicePath = bootServices->LocateDevicePath;
  83. LoadImage = bootServices->LoadImage;
  84. StartImage = bootServices->StartImage;
  85. //
  86. // Stash some of the Runtime services pointers
  87. //
  88. runtimeServices = SystemTable->RuntimeServices;
  89. SetVariable = runtimeServices->SetVariable;
  90. }
  91. EFI_STATUS
  92. Init(
  93. IN EFI_HANDLE ImageHandle,
  94. IN EFI_SYSTEM_TABLE *SystemTable
  95. )
  96. {
  97. EFI_STATUS Status;
  98. UINTN BufferSize;
  99. do {
  100. //
  101. // Initialize EFI routines
  102. //
  103. InitializeProtocols( SystemTable );
  104. InitializeStdOut( SystemTable );
  105. InitializeLib( ImageHandle, SystemTable );
  106. //
  107. // Save Image Handle
  108. //
  109. MenuImageHandle = ImageHandle;
  110. BS->HandleProtocol (ImageHandle, &LoadedImageProtocol, &ExeImage);
  111. //
  112. //
  113. //
  114. NvrOrder = AllocatePool(MAX_ENV_SIZE + 32);
  115. if (! NvrOrder) {
  116. Status = EFI_OUT_OF_RESOURCES;
  117. break;
  118. }
  119. //
  120. // get boot order from nvram
  121. //
  122. BufferSize = MAX_ENV_SIZE;
  123. Status = RT->GetVariable (
  124. VarBootOrder,
  125. &EfiGlobalVariable,
  126. &NvrAttributes,
  127. &BufferSize,
  128. NvrOrder
  129. );
  130. if (EFI_ERROR(Status)) {
  131. Print(L"Nvr: failed to load boot order array. defaulting\n");
  132. BufferSize = 0;
  133. NvrAttributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
  134. Status = EFI_SUCCESS;
  135. }
  136. //
  137. // get how many boot options there are
  138. //
  139. NvrOrderCount = BufferSize / sizeof(UINT16);
  140. } while ( FALSE );
  141. return Status;
  142. }
  143. VOID
  144. Shutdown(
  145. VOID
  146. )
  147. {
  148. if (NvrOrder) {
  149. FreePool(NvrOrder);
  150. }
  151. }
  152. EFI_STATUS
  153. EfiMain(
  154. IN EFI_HANDLE ImageHandle,
  155. IN EFI_SYSTEM_TABLE *SystemTable
  156. )
  157. {
  158. EFI_STATUS Status;
  159. UINT32 ch, user, cnt;
  160. CHAR8 *LangCode;
  161. // Initialize the EFI SDX libraries
  162. InitializeLib( ImageHandle, SystemTable );
  163. //
  164. //
  165. //
  166. LangCode = LibGetVariable (VarLanguage, &EfiGlobalVariable);
  167. if (LangCode) {
  168. UINTN i;
  169. Print(L"LangCode: ");
  170. for (i = 0; i < ISO_639_2_ENTRY_SIZE; i++) {
  171. Print(L"%c", LangCode[i]);
  172. }
  173. Print(L"\n");
  174. FreePool(LangCode);
  175. }
  176. //
  177. //
  178. //
  179. Status = Init(ImageHandle, SystemTable);
  180. if (EFI_ERROR(Status)) {
  181. return TRUE;
  182. }
  183. //
  184. //
  185. //
  186. ch = cnt = 0;
  187. user = 0;
  188. while ( user != (UINT32) 'q' && ch <= (UINT32) 0xFF ) {
  189. Print( L"Please press any key to continue (q to quit)\n");
  190. user = GetInputKey();
  191. if (user == L'q') {
  192. break;
  193. }
  194. Print(L"Adding a boot entry\n");
  195. RestoreNvr(L"blob.nvr");
  196. }
  197. //
  198. // clean up
  199. //
  200. Shutdown();
  201. // If you return the status, EFI will kindly give the user an English
  202. // error message.
  203. return TRUE;
  204. }
  205. UINT32 GetInputKey()
  206. {
  207. EFI_INPUT_KEY pKey;
  208. EFI_STATUS Status;
  209. // Wait until a keystroke is available
  210. WaitForSingleEvent(
  211. ST->ConIn->WaitForKey,
  212. 0);
  213. // Read the key that has been pressed
  214. Status = ST->ConIn->ReadKeyStroke(
  215. ST->ConIn,
  216. &pKey);
  217. if (EFI_ERROR(Status) || pKey.ScanCode != 0) {
  218. return 0x20; // space
  219. }
  220. return pKey.UnicodeChar;
  221. }
  222. EFI_STATUS
  223. InsertBootOption(
  224. VOID *BootOption,
  225. UINT64 BootOptionSize
  226. )
  227. {
  228. EFI_STATUS Status;
  229. CHAR16 OptionStr[40];
  230. Print(L"InsertBootOption: enter\n");
  231. //
  232. // attempt to insert boot option
  233. //
  234. do {
  235. UINT16 Target;
  236. //
  237. //
  238. //
  239. Status = FindFreeBootOption(&Target);
  240. if (EFI_ERROR(Status)) {
  241. Print (L"Nvr: failed to find free boot option id: %hr\n", Status);
  242. break;
  243. }
  244. //
  245. // update nvram with the new boot option
  246. //
  247. SPrint( OptionStr, sizeof(OptionStr), VarBootOption, Target);
  248. Print(L"InsertBootOption: target = %x, OptionStr = %s\n", Target, OptionStr);
  249. Status = RT->SetVariable (
  250. OptionStr,
  251. &EfiGlobalVariable,
  252. NvrAttributes,
  253. BootOptionSize,
  254. BootOption
  255. );
  256. if (EFI_ERROR(Status)) {
  257. Print (L"Nvr: failed to add %hs - %hr\n", OptionStr, Status);
  258. break;
  259. }
  260. //
  261. // replace boot order with one including the new option
  262. //
  263. NvrOrder[NvrOrderCount] = Target;
  264. NvrOrderCount++;
  265. Status = RT->SetVariable (
  266. VarBootOrder,
  267. &EfiGlobalVariable,
  268. NvrAttributes,
  269. NvrOrderCount * sizeof(UINT16),
  270. NvrOrder
  271. );
  272. if (EFI_ERROR(Status)) {
  273. Print (L"Nvr: failed to update %hs - %hr\n", VarBootOrder, Status);
  274. break;
  275. }
  276. #if 1
  277. //
  278. // validate what we just wrote
  279. //
  280. {
  281. UINTN BlobSize;
  282. CHAR8 *Blob;
  283. UINT16 i;
  284. BlobSize = BootOptionSize;
  285. Blob = AllocatePool(BootOptionSize);
  286. do {
  287. Status = RT->GetVariable (
  288. OptionStr,
  289. &EfiGlobalVariable,
  290. NULL,
  291. &BlobSize,
  292. Blob
  293. );
  294. if (EFI_ERROR(Status)) {
  295. Print (L"Nvr: failed to read comparison blob: %hr\n", Status);
  296. break;
  297. }
  298. for (i = 0; i < BootOptionSize; i++) {
  299. if (((CHAR8*)BootOption)[i] != Blob[i]) {
  300. Print(L"Nvr: diff[%d]: BootOption = %d, Blob = %d\n", i, ((CHAR8*)BootOption)[i], Blob[i]);
  301. }
  302. }
  303. } while ( FALSE );
  304. FreePool(Blob);
  305. }
  306. #endif
  307. } while ( FALSE );
  308. Print(L"InsertBootOption: exit\n");
  309. return Status;
  310. }
  311. EFI_STATUS
  312. FindFreeBootOption(
  313. CHAR16 *FreeIdx
  314. )
  315. {
  316. EFI_STATUS Status;
  317. UINT16 id;
  318. UINT16 i;
  319. BOOLEAN Found;
  320. BOOLEAN HaveFreeIdx;
  321. Print(L"FindFreeBootOption: enter\n");
  322. HaveFreeIdx = FALSE;
  323. *FreeIdx = MAXUSHORT;
  324. //
  325. // use a brute force search to find a new boot option id
  326. //
  327. for ( id = 0; id <= MAXUSHORT; id++ ) {
  328. Print(L"FindFreeBootOption: id = %x\n", id);
  329. Found = FALSE;
  330. for (i = 0; i < NvrOrderCount; i++) {
  331. if (NvrOrder[i] == id) {
  332. Found = TRUE;
  333. break;
  334. }
  335. }
  336. if (! Found) {
  337. *FreeIdx = id;
  338. HaveFreeIdx = TRUE;
  339. break;
  340. }
  341. }
  342. if (HaveFreeIdx) {
  343. Status = EFI_SUCCESS;
  344. } else {
  345. Status = EFI_OUT_OF_RESOURCES;
  346. }
  347. Print(L"FindFreeBootOption: FreeIdx = %x, status = %x\n", *FreeIdx, Status);
  348. Print(L"FindFreeBootOption: exit\n");
  349. return Status;
  350. }
  351. INTN
  352. RestoreNvr (
  353. CHAR16* fileName
  354. )
  355. {
  356. EFI_STATUS Status;
  357. EFI_FILE_HANDLE nvrFile;
  358. //
  359. // Read from saved boot options file
  360. //
  361. Status = OpenCreateFile (EFI_FILE_MODE_READ,&nvrFile,fileName);
  362. if (EFI_ERROR (Status)) {
  363. Print(L"\nCan not open the file %s\n",fileName);
  364. return Status;
  365. }
  366. //
  367. // This updates nvram with saved boot options
  368. //
  369. return (ParseNvrFile (nvrFile));
  370. }
  371. EFI_STATUS
  372. OpenCreateFile (
  373. UINT64 OCFlags,
  374. EFI_FILE_HANDLE* StartHdl,
  375. CHAR16* Name
  376. )
  377. {
  378. EFI_FILE_IO_INTERFACE *Vol;
  379. EFI_FILE_HANDLE RootFs;
  380. EFI_FILE_HANDLE CurDir;
  381. EFI_FILE_HANDLE FileHandle;
  382. CHAR16 FileName[100],*DevicePathAsString;
  383. EFI_STATUS Status;
  384. Print(L"OpenCreateFile: enter\n");
  385. do {
  386. //
  387. // Open the volume for the device where the nvrutil was started.
  388. //
  389. Status = BS->HandleProtocol (
  390. ExeImage->DeviceHandle,
  391. &FileSystemProtocol,
  392. &Vol
  393. );
  394. if (EFI_ERROR(Status)) {
  395. Print(L"\n");
  396. Print(L"Can not get a FileSystem handle for %s DeviceHandle\n",ExeImage->FilePath);
  397. break;
  398. }
  399. Status = Vol->OpenVolume (Vol, &RootFs);
  400. if (EFI_ERROR(Status)) {
  401. Print(L"\n");
  402. Print(L"Can not open the volume for the file system\n");
  403. break;
  404. }
  405. CurDir = RootFs;
  406. //
  407. // Open saved boot options file
  408. //
  409. FileName[0] = 0;
  410. DevicePathAsString = DevicePathToStr(ExeImage->FilePath);
  411. if (DevicePathAsString!=NULL) {
  412. StrCpy(FileName,DevicePathAsString);
  413. FreePool(DevicePathAsString);
  414. }
  415. StrCpy(FileName, L".\\");
  416. StrCat(FileName,Name);
  417. Status = CurDir->Open (CurDir,
  418. &FileHandle,
  419. FileName,
  420. OCFlags,
  421. 0
  422. );
  423. *StartHdl=FileHandle;
  424. } while ( FALSE );
  425. Print(L"OpenCreateFile: exit\n");
  426. return Status;
  427. }
  428. INTN
  429. ParseNvrFile (
  430. EFI_FILE_HANDLE NvrFile
  431. )
  432. {
  433. BOOLEAN bSuccess;
  434. EFI_STATUS Status;
  435. CHAR8 *buffer;
  436. UINTN k,size;
  437. UINT64 BootNumber;
  438. UINT64 BootSize;
  439. VOID *BootOption;
  440. UINTN blockBegin;
  441. EFI_FILE_INFO *fileInfo;
  442. Print(L"ParseNvrFile: enter\n");
  443. buffer = NULL;
  444. do {
  445. //
  446. //
  447. //
  448. size = 0;
  449. Status = NvrFile->GetInfo(NvrFile,&GenericFileInfo,&size,NULL);
  450. if (Status != EFI_BUFFER_TOO_SMALL) {
  451. break;
  452. }
  453. Print(L"ParseNvrFile: size = %d vs %d\n", size, SIZE_OF_EFI_FILE_INFO+255*sizeof (CHAR16));
  454. fileInfo = AllocateZeroPool(size);
  455. if (fileInfo == NULL) {
  456. Print(L"\n");
  457. Print (L"Failed to allocate memory for File Info buffer!\n");
  458. Status = EFI_OUT_OF_RESOURCES;
  459. break;
  460. }
  461. //
  462. //
  463. //
  464. Status = NvrFile->GetInfo(NvrFile,&GenericFileInfo,&size,fileInfo);
  465. size=(UINTN) fileInfo->FileSize;
  466. FreePool (fileInfo);
  467. buffer = AllocateZeroPool ((size+1));
  468. if (buffer == NULL) {
  469. Print(L"\n");
  470. Print (L"Failed to allocate memory for File buffer!\n");
  471. Status = EFI_OUT_OF_RESOURCES;
  472. break;
  473. }
  474. Status = NvrFile->Read(NvrFile,&size,buffer);
  475. NvrFile->Close (NvrFile);
  476. if (EFI_ERROR (Status)) {
  477. Print(L"\n");
  478. Print (L"Failed to read nvr file!\n");
  479. break;
  480. }
  481. //
  482. //
  483. //
  484. k=0;
  485. while(k < size ) {
  486. blockBegin = k;
  487. CopyMem( &BootNumber, &buffer[k], sizeof(BootNumber));
  488. k += sizeof(UINT64);
  489. CopyMem( &BootSize, &buffer[k], sizeof(BootSize));
  490. k += sizeof(UINT64);
  491. BootOption = (VOID *)((CHAR8*)buffer + k);
  492. k += BootSize;
  493. //
  494. // sanity check the file position vs. what the
  495. // file header information tells us. The value
  496. // k should be <= to size now.
  497. //
  498. if (k > size) {
  499. Print (L"\nThe NVRAM file is corrupted.\n");
  500. Status = EFI_BAD_BUFFER_SIZE;
  501. break;
  502. }
  503. //
  504. // write the current boot entry at free location
  505. //
  506. Status = InsertBootOption(
  507. BootOption,
  508. BootSize
  509. );
  510. if (EFI_ERROR(Status)) {
  511. Print(L"\nError: Failed to append new boot entry to boot order array\n");
  512. break;
  513. }
  514. }
  515. } while ( FALSE );
  516. if (buffer) {
  517. FreePool (buffer);
  518. }
  519. Print(L"ParseNvrFile: exit\n");
  520. return Status;
  521. }