CapsuleOnDisk.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818
  1. /** @file
  2. Process Capsule On Disk.
  3. Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include <Uefi.h>
  7. #include <Library/BaseLib.h>
  8. #include <Library/DebugLib.h>
  9. #include <Library/BaseMemoryLib.h>
  10. #include <Library/MemoryAllocationLib.h>
  11. #include <Library/UefiBootServicesTableLib.h>
  12. #include <Library/UefiRuntimeServicesTableLib.h>
  13. #include <Library/UefiLib.h>
  14. #include <Library/PrintLib.h>
  15. #include <Library/DevicePathLib.h>
  16. #include <Library/FileHandleLib.h>
  17. #include <Library/UefiBootManagerLib.h>
  18. #include <Protocol/SimpleFileSystem.h>
  19. #include <Protocol/Shell.h>
  20. #include <Guid/FileInfo.h>
  21. #include <Guid/GlobalVariable.h>
  22. #include <Guid/Gpt.h>
  23. EFI_GUID mCapsuleOnDiskBootOptionGuid = { 0x4CC29BB7, 0x2413, 0x40A2, { 0xB0, 0x6D, 0x25, 0x3E, 0x37, 0x10, 0xF5, 0x32 } };
  24. /**
  25. Get shell protocol.
  26. @return Pointer to shell protocol.
  27. **/
  28. EFI_SHELL_PROTOCOL *
  29. GetShellProtocol (
  30. VOID
  31. );
  32. /**
  33. Get file name from file path.
  34. @param FilePath File path.
  35. @return Pointer to file name.
  36. **/
  37. CHAR16 *
  38. GetFileNameFromPath (
  39. CHAR16 *FilePath
  40. )
  41. {
  42. EFI_STATUS Status;
  43. EFI_SHELL_PROTOCOL *ShellProtocol;
  44. SHELL_FILE_HANDLE Handle;
  45. EFI_FILE_INFO *FileInfo;
  46. ShellProtocol = GetShellProtocol ();
  47. if (ShellProtocol == NULL) {
  48. return NULL;
  49. }
  50. //
  51. // Open file by FileName.
  52. //
  53. Status = ShellProtocol->OpenFileByName (
  54. FilePath,
  55. &Handle,
  56. EFI_FILE_MODE_READ
  57. );
  58. if (EFI_ERROR (Status)) {
  59. return NULL;
  60. }
  61. //
  62. // Get file name from EFI_FILE_INFO.
  63. //
  64. FileInfo = ShellProtocol->GetFileInfo (Handle);
  65. ShellProtocol->CloseFile (Handle);
  66. if (FileInfo == NULL) {
  67. return NULL;
  68. }
  69. return FileInfo->FileName;
  70. }
  71. /**
  72. Check if the device path is EFI system Partition.
  73. @param DevicePath The ESP device path.
  74. @retval TRUE DevicePath is a device path for ESP.
  75. @retval FALSE DevicePath is not a device path for ESP.
  76. **/
  77. BOOLEAN
  78. IsEfiSysPartitionDevicePath (
  79. EFI_DEVICE_PATH_PROTOCOL *DevicePath
  80. )
  81. {
  82. EFI_STATUS Status;
  83. EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
  84. HARDDRIVE_DEVICE_PATH *Hd;
  85. EFI_HANDLE Handle;
  86. //
  87. // Check if the device path contains GPT node
  88. //
  89. TempDevicePath = DevicePath;
  90. while (!IsDevicePathEnd (TempDevicePath)) {
  91. if ((DevicePathType (TempDevicePath) == MEDIA_DEVICE_PATH) &&
  92. (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP)) {
  93. Hd = (HARDDRIVE_DEVICE_PATH *)TempDevicePath;
  94. if (Hd->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER) {
  95. break;
  96. }
  97. }
  98. TempDevicePath = NextDevicePathNode (TempDevicePath);
  99. }
  100. if (!IsDevicePathEnd (TempDevicePath)) {
  101. //
  102. // Search for EFI system partition protocol on full device path in Boot Option
  103. //
  104. Status = gBS->LocateDevicePath (&gEfiPartTypeSystemPartGuid, &DevicePath, &Handle);
  105. return EFI_ERROR (Status) ? FALSE : TRUE;
  106. } else {
  107. return FALSE;
  108. }
  109. }
  110. /**
  111. Dump all EFI System Partition.
  112. **/
  113. VOID
  114. DumpAllEfiSysPartition (
  115. VOID
  116. )
  117. {
  118. EFI_HANDLE *SimpleFileSystemHandles;
  119. UINTN NumberSimpleFileSystemHandles;
  120. UINTN Index;
  121. EFI_DEVICE_PATH_PROTOCOL *DevicePath;
  122. UINTN NumberEfiSystemPartitions;
  123. EFI_SHELL_PROTOCOL *ShellProtocol;
  124. NumberEfiSystemPartitions = 0;
  125. ShellProtocol = GetShellProtocol ();
  126. if (ShellProtocol == NULL) {
  127. Print (L"Get Shell Protocol Fail\n");;
  128. return ;
  129. }
  130. Print (L"EFI System Partition list:\n");
  131. gBS->LocateHandleBuffer (
  132. ByProtocol,
  133. &gEfiSimpleFileSystemProtocolGuid,
  134. NULL,
  135. &NumberSimpleFileSystemHandles,
  136. &SimpleFileSystemHandles
  137. );
  138. for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
  139. DevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
  140. if (IsEfiSysPartitionDevicePath (DevicePath)) {
  141. NumberEfiSystemPartitions++;
  142. Print(L" %s\n %s\n", ShellProtocol->GetMapFromDevicePath (&DevicePath), ConvertDevicePathToText (DevicePath, TRUE, TRUE));
  143. }
  144. }
  145. if (NumberEfiSystemPartitions == 0) {
  146. Print(L" No ESP found.\n");
  147. }
  148. }
  149. /**
  150. Check if capsule is provisioned.
  151. @retval TRUE Capsule is provisioned previously.
  152. @retval FALSE No capsule is provisioned.
  153. **/
  154. BOOLEAN
  155. IsCapsuleProvisioned (
  156. VOID
  157. )
  158. {
  159. EFI_STATUS Status;
  160. UINT64 OsIndication;
  161. UINTN DataSize;
  162. OsIndication = 0;
  163. DataSize = sizeof(UINT64);
  164. Status = gRT->GetVariable (
  165. L"OsIndications",
  166. &gEfiGlobalVariableGuid,
  167. NULL,
  168. &DataSize,
  169. &OsIndication
  170. );
  171. if (!EFI_ERROR (Status) &&
  172. (OsIndication & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) != 0) {
  173. return TRUE;
  174. }
  175. return FALSE;
  176. }
  177. /**
  178. Get one active Efi System Partition.
  179. @param[out] FsDevicePath The device path of Fs
  180. @param[out] Fs The file system within EfiSysPartition
  181. @retval EFI_SUCCESS Get file system successfully
  182. @retval EFI_NOT_FOUND No valid file system found
  183. **/
  184. EFI_STATUS
  185. GetEfiSysPartition (
  186. OUT EFI_DEVICE_PATH_PROTOCOL **FsDevicePath,
  187. OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs
  188. )
  189. {
  190. EFI_HANDLE *SimpleFileSystemHandles;
  191. UINTN NumberSimpleFileSystemHandles;
  192. UINTN Index;
  193. EFI_DEVICE_PATH_PROTOCOL *DevicePath;
  194. EFI_STATUS Status;
  195. Status = gBS->LocateHandleBuffer (
  196. ByProtocol,
  197. &gEfiSimpleFileSystemProtocolGuid,
  198. NULL,
  199. &NumberSimpleFileSystemHandles,
  200. &SimpleFileSystemHandles
  201. );
  202. if (EFI_ERROR (Status)) {
  203. return EFI_NOT_FOUND;
  204. }
  205. for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
  206. DevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
  207. if (IsEfiSysPartitionDevicePath (DevicePath)) {
  208. Status = gBS->HandleProtocol (SimpleFileSystemHandles[Index], &gEfiSimpleFileSystemProtocolGuid, (VOID **)Fs);
  209. if (!EFI_ERROR (Status)) {
  210. *FsDevicePath = DevicePath;
  211. return EFI_SUCCESS;
  212. }
  213. }
  214. }
  215. return EFI_NOT_FOUND;
  216. }
  217. /**
  218. Check if Active Efi System Partition within GPT is in the device path.
  219. @param[in] DevicePath The device path
  220. @param[out] FsDevicePath The device path of Fs
  221. @param[out] Fs The file system within EfiSysPartition
  222. @retval EFI_SUCCESS Get file system successfully
  223. @retval EFI_NOT_FOUND No valid file system found
  224. @retval others Get file system failed
  225. **/
  226. EFI_STATUS
  227. GetEfiSysPartitionFromDevPath (
  228. IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
  229. OUT EFI_DEVICE_PATH_PROTOCOL **FsDevicePath,
  230. OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs
  231. )
  232. {
  233. EFI_STATUS Status;
  234. EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
  235. HARDDRIVE_DEVICE_PATH *Hd;
  236. EFI_HANDLE Handle;
  237. //
  238. // Check if the device path contains GPT node
  239. //
  240. TempDevicePath = DevicePath;
  241. while (!IsDevicePathEnd (TempDevicePath)) {
  242. if ((DevicePathType (TempDevicePath) == MEDIA_DEVICE_PATH) &&
  243. (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP)) {
  244. Hd = (HARDDRIVE_DEVICE_PATH *)TempDevicePath;
  245. if (Hd->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER) {
  246. break;
  247. }
  248. }
  249. TempDevicePath = NextDevicePathNode (TempDevicePath);
  250. }
  251. if (!IsDevicePathEnd (TempDevicePath)) {
  252. //
  253. // Search for EFI system partition protocol on full device path in Boot Option
  254. //
  255. Status = gBS->LocateDevicePath (&gEfiPartTypeSystemPartGuid, &DevicePath, &Handle);
  256. //
  257. // Search for simple file system on this handler
  258. //
  259. if (!EFI_ERROR (Status)) {
  260. Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)Fs);
  261. if (!EFI_ERROR (Status)) {
  262. *FsDevicePath = DevicePathFromHandle (Handle);
  263. return EFI_SUCCESS;
  264. }
  265. }
  266. }
  267. return EFI_NOT_FOUND;
  268. }
  269. /**
  270. Get SimpleFileSystem from boot option file path.
  271. @param[in] DevicePath The file path of boot option
  272. @param[out] FullPath The full device path of boot device
  273. @param[out] Fs The file system within EfiSysPartition
  274. @retval EFI_SUCCESS Get file system successfully
  275. @retval EFI_NOT_FOUND No valid file system found
  276. @retval others Get file system failed
  277. **/
  278. EFI_STATUS
  279. EFIAPI
  280. GetEfiSysPartitionFromBootOptionFilePath (
  281. IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
  282. OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
  283. OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs
  284. )
  285. {
  286. EFI_STATUS Status;
  287. EFI_DEVICE_PATH_PROTOCOL *CurFullPath;
  288. EFI_DEVICE_PATH_PROTOCOL *PreFullPath;
  289. EFI_DEVICE_PATH_PROTOCOL *FsFullPath;
  290. CurFullPath = NULL;
  291. FsFullPath = NULL;
  292. //
  293. // Try every full device Path generated from bootoption
  294. //
  295. do {
  296. PreFullPath = CurFullPath;
  297. CurFullPath = EfiBootManagerGetNextLoadOptionDevicePath (DevicePath, CurFullPath);
  298. if (PreFullPath != NULL) {
  299. FreePool (PreFullPath);
  300. }
  301. if (CurFullPath == NULL) {
  302. //
  303. // No Active EFI system partition is found in BootOption device path
  304. //
  305. Status = EFI_NOT_FOUND;
  306. break;
  307. }
  308. DEBUG_CODE (
  309. CHAR16 *DevicePathStr;
  310. DevicePathStr = ConvertDevicePathToText (CurFullPath, TRUE, TRUE);
  311. if (DevicePathStr != NULL){
  312. DEBUG ((DEBUG_INFO, "Full device path %s\n", DevicePathStr));
  313. FreePool (DevicePathStr);
  314. }
  315. );
  316. Status = GetEfiSysPartitionFromDevPath (CurFullPath, &FsFullPath, Fs);
  317. } while (EFI_ERROR (Status));
  318. if (*Fs != NULL) {
  319. *FullPath = FsFullPath;
  320. return EFI_SUCCESS;
  321. } else {
  322. return EFI_NOT_FOUND;
  323. }
  324. }
  325. /**
  326. Get a valid SimpleFileSystem within EFI system partition.
  327. @param[in] Map The FS mapping capsule write to
  328. @param[out] BootNext The value of BootNext Variable
  329. @param[out] Fs The file system within EfiSysPartition
  330. @param[out] UpdateBootNext The flag to indicate whether update BootNext Variable
  331. @retval EFI_SUCCESS Get FS successfully
  332. @retval EFI_NOT_FOUND No valid FS found
  333. @retval others Get FS failed
  334. **/
  335. EFI_STATUS
  336. EFIAPI
  337. GetUpdateFileSystem (
  338. IN CHAR16 *Map,
  339. OUT UINT16 *BootNext,
  340. OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs,
  341. OUT BOOLEAN *UpdateBootNext
  342. )
  343. {
  344. EFI_STATUS Status;
  345. CHAR16 BootOptionName[20];
  346. UINTN Index;
  347. CONST EFI_DEVICE_PATH_PROTOCOL *MappedDevicePath;
  348. EFI_DEVICE_PATH_PROTOCOL *DevicePath;
  349. EFI_DEVICE_PATH_PROTOCOL *FullPath;
  350. UINT16 *BootNextData;
  351. EFI_BOOT_MANAGER_LOAD_OPTION BootNextOption;
  352. EFI_BOOT_MANAGER_LOAD_OPTION *BootOptionBuffer;
  353. UINTN BootOptionCount;
  354. EFI_SHELL_PROTOCOL *ShellProtocol;
  355. EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
  356. MappedDevicePath = NULL;
  357. BootOptionBuffer = NULL;
  358. ShellProtocol = GetShellProtocol ();
  359. if (ShellProtocol == NULL) {
  360. Print (L"Get Shell Protocol Fail\n");;
  361. return EFI_NOT_FOUND;
  362. }
  363. //
  364. // 1. If Fs is not assigned and there are capsule provisioned before,
  365. // Get EFI system partition from BootNext.
  366. //
  367. if (IsCapsuleProvisioned () && Map == NULL) {
  368. Status = GetVariable2 (
  369. L"BootNext",
  370. &gEfiGlobalVariableGuid,
  371. (VOID **)&BootNextData,
  372. NULL
  373. );
  374. if (EFI_ERROR (Status) || BootNextData == NULL) {
  375. Print (L"Get Boot Next Data Fail. Status = %r\n", Status);
  376. return EFI_NOT_FOUND;
  377. } else {
  378. UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", *BootNextData);
  379. Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootNextOption);
  380. if (!EFI_ERROR (Status)) {
  381. DevicePath = BootNextOption.FilePath;
  382. Status = GetEfiSysPartitionFromBootOptionFilePath (DevicePath, &FullPath, Fs);
  383. if (!EFI_ERROR (Status)) {
  384. *UpdateBootNext = FALSE;
  385. Print(L"Get EFI system partition from BootNext : %s\n", BootNextOption.Description);
  386. Print(L"%s %s\n", ShellProtocol->GetMapFromDevicePath (&FullPath), ConvertDevicePathToText (FullPath, TRUE, TRUE));
  387. return EFI_SUCCESS;
  388. }
  389. }
  390. }
  391. }
  392. //
  393. // Check if Map is valid.
  394. //
  395. if (Map != NULL) {
  396. MappedDevicePath = ShellProtocol->GetDevicePathFromMap (Map);
  397. if (MappedDevicePath == NULL) {
  398. Print(L"'%s' is not a valid mapping.\n", Map);
  399. return EFI_INVALID_PARAMETER;
  400. } else if (!IsEfiSysPartitionDevicePath (DuplicateDevicePath (MappedDevicePath))) {
  401. Print(L"'%s' is not a EFI System Partition.\n", Map);
  402. return EFI_INVALID_PARAMETER;
  403. }
  404. }
  405. //
  406. // 2. Get EFI system partition form boot options.
  407. //
  408. BootOptionBuffer = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
  409. if ( (BootOptionBuffer == NULL) ||
  410. (BootOptionCount == 0 && Map == NULL)
  411. ) {
  412. return EFI_NOT_FOUND;
  413. }
  414. for (Index = 0; Index < BootOptionCount; Index++) {
  415. //
  416. // Get the boot option from the link list
  417. //
  418. DevicePath = BootOptionBuffer[Index].FilePath;
  419. //
  420. // Skip inactive or legacy boot options
  421. //
  422. if ((BootOptionBuffer[Index].Attributes & LOAD_OPTION_ACTIVE) == 0 ||
  423. DevicePathType (DevicePath) == BBS_DEVICE_PATH) {
  424. continue;
  425. }
  426. DEBUG_CODE (
  427. CHAR16 *DevicePathStr;
  428. DevicePathStr = ConvertDevicePathToText (DevicePath, TRUE, TRUE);
  429. if (DevicePathStr != NULL){
  430. DEBUG ((DEBUG_INFO, "Try BootOption %s\n", DevicePathStr));
  431. FreePool (DevicePathStr);
  432. } else {
  433. DEBUG ((DEBUG_INFO, "DevicePathToStr failed\n"));
  434. }
  435. );
  436. Status = GetEfiSysPartitionFromBootOptionFilePath (DevicePath, &FullPath, Fs);
  437. if (!EFI_ERROR (Status)) {
  438. if (Map == NULL) {
  439. *BootNext = (UINT16) BootOptionBuffer[Index].OptionNumber;
  440. *UpdateBootNext = TRUE;
  441. Print (L"Found EFI system partition on Boot%04x: %s\n", *BootNext, BootOptionBuffer[Index].Description);
  442. Print (L"%s %s\n", ShellProtocol->GetMapFromDevicePath (&FullPath), ConvertDevicePathToText (FullPath, TRUE, TRUE));
  443. return EFI_SUCCESS;
  444. }
  445. if (StrnCmp (Map, ShellProtocol->GetMapFromDevicePath (&FullPath), StrLen (Map)) == 0) {
  446. *BootNext = (UINT16) BootOptionBuffer[Index].OptionNumber;
  447. *UpdateBootNext = TRUE;
  448. Print (L"Found Boot Option on %s : %s\n", Map, BootOptionBuffer[Index].Description);
  449. return EFI_SUCCESS;
  450. }
  451. }
  452. }
  453. //
  454. // 3. If no ESP is found on boot option, try to find a ESP and create boot option for it.
  455. //
  456. if (Map != NULL) {
  457. //
  458. // If map is assigned, try to get ESP from mapped Fs.
  459. //
  460. DevicePath = DuplicateDevicePath (MappedDevicePath);
  461. Status = GetEfiSysPartitionFromDevPath (DevicePath, &FullPath, Fs);
  462. if (EFI_ERROR (Status)) {
  463. Print (L"Error: Cannot get EFI system partiion from '%s' - %r\n", Map, Status);
  464. return EFI_NOT_FOUND;
  465. }
  466. Print (L"Warning: Cannot find Boot Option on '%s'!\n", Map);
  467. } else {
  468. Status = GetEfiSysPartition (&DevicePath, Fs);
  469. if (EFI_ERROR (Status)) {
  470. Print (L"Error: Cannot find a EFI system partition!\n");
  471. return EFI_NOT_FOUND;
  472. }
  473. }
  474. Print (L"Create Boot option for capsule on disk:\n");
  475. Status = EfiBootManagerInitializeLoadOption (
  476. &NewOption,
  477. LoadOptionNumberUnassigned,
  478. LoadOptionTypeBoot,
  479. LOAD_OPTION_ACTIVE,
  480. L"UEFI Capsule On Disk",
  481. DevicePath,
  482. (UINT8 *) &mCapsuleOnDiskBootOptionGuid,
  483. sizeof(EFI_GUID)
  484. );
  485. if (!EFI_ERROR (Status)) {
  486. Status = EfiBootManagerAddLoadOptionVariable (&NewOption, (UINTN) -1); {
  487. if (!EFI_ERROR (Status)) {
  488. *UpdateBootNext = TRUE;
  489. *BootNext = (UINT16) NewOption.OptionNumber;
  490. Print (L" Boot%04x: %s\n", *BootNext, ConvertDevicePathToText(DevicePath, TRUE, TRUE));
  491. return EFI_SUCCESS;
  492. }
  493. }
  494. }
  495. Print (L"ERROR: Cannot create boot option! - %r\n", Status);
  496. return EFI_NOT_FOUND;
  497. }
  498. /**
  499. Write files to a given SimpleFileSystem.
  500. @param[in] Buffer The buffer array
  501. @param[in] BufferSize The buffer size array
  502. @param[in] FileName The file name array
  503. @param[in] BufferNum The buffer number
  504. @param[in] Fs The SimpleFileSystem handle to be written
  505. @retval EFI_SUCCESS Write file successfully
  506. @retval EFI_NOT_FOUND SFS protocol not found
  507. @retval others Write file failed
  508. **/
  509. EFI_STATUS
  510. WriteUpdateFile (
  511. IN VOID **Buffer,
  512. IN UINTN *BufferSize,
  513. IN CHAR16 **FileName,
  514. IN UINTN BufferNum,
  515. IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs
  516. )
  517. {
  518. EFI_STATUS Status;
  519. EFI_FILE *Root;
  520. EFI_FILE *FileHandle;
  521. EFI_FILE_PROTOCOL *DirHandle;
  522. UINT64 FileInfo;
  523. VOID *Filebuffer;
  524. UINTN FileSize;
  525. UINTN Index;
  526. DirHandle = NULL;
  527. FileHandle = NULL;
  528. Index = 0;
  529. //
  530. // Open Root from SFS
  531. //
  532. Status = Fs->OpenVolume (Fs, &Root);
  533. if (EFI_ERROR (Status)) {
  534. Print (L"Cannot open volume. Status = %r\n", Status);
  535. return EFI_NOT_FOUND;
  536. }
  537. //
  538. // Ensure that efi and updatecapsule directories exist
  539. //
  540. Status = Root->Open (Root, &DirHandle, L"\\EFI", EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
  541. if (EFI_ERROR (Status)) {
  542. Status = Root->Open (Root, &DirHandle, L"\\EFI", EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, EFI_FILE_DIRECTORY);
  543. if (EFI_ERROR (Status)) {
  544. Print(L"Unable to create %s directory\n", L"\\EFI");
  545. return EFI_NOT_FOUND;
  546. }
  547. }
  548. Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE , 0);
  549. if (EFI_ERROR (Status)) {
  550. Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, EFI_FILE_DIRECTORY);
  551. if (EFI_ERROR (Status)) {
  552. Print(L"Unable to create %s directory\n", EFI_CAPSULE_FILE_DIRECTORY);
  553. return EFI_NOT_FOUND;
  554. }
  555. }
  556. for (Index = 0; Index < BufferNum; Index++) {
  557. FileHandle = NULL;
  558. //
  559. // Open UpdateCapsule file
  560. //
  561. Status = DirHandle->Open (DirHandle, &FileHandle, FileName[Index], EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, 0);
  562. if (EFI_ERROR (Status)) {
  563. Print (L"Unable to create %s file\n", FileName[Index]);
  564. return EFI_NOT_FOUND;
  565. }
  566. //
  567. // Empty the file contents
  568. //
  569. Status = FileHandleGetSize (FileHandle, &FileInfo);
  570. if (EFI_ERROR (Status)) {
  571. FileHandleClose (FileHandle);
  572. Print (L"Error Reading %s\n", FileName[Index]);
  573. return EFI_DEVICE_ERROR;
  574. }
  575. //
  576. // If the file size is already 0, then it has been empty.
  577. //
  578. if (FileInfo != 0) {
  579. //
  580. // Set the file size to 0.
  581. //
  582. FileInfo = 0;
  583. Status = FileHandleSetSize (FileHandle, FileInfo);
  584. if (EFI_ERROR (Status)) {
  585. Print (L"Error Deleting %s\n", FileName[Index]);
  586. FileHandleClose (FileHandle);
  587. return Status;
  588. }
  589. }
  590. //
  591. // Write Filebuffer to file
  592. //
  593. Filebuffer = Buffer[Index];
  594. FileSize = BufferSize[Index];
  595. Status = FileHandleWrite (FileHandle, &FileSize, Filebuffer);
  596. if (EFI_ERROR (Status)) {
  597. Print (L"Unable to write Capsule Update to %s, Status = %r\n", FileName[Index], Status);
  598. return EFI_NOT_FOUND;
  599. }
  600. Print (L"Succeed to write %s\n", FileName[Index]);
  601. FileHandleClose (FileHandle);
  602. }
  603. return EFI_SUCCESS;
  604. }
  605. /**
  606. Set capsule status variable.
  607. @param[in] SetCap Set or clear the capsule flag.
  608. @retval EFI_SUCCESS Succeed to set SetCap variable.
  609. @retval others Fail to set the variable.
  610. **/
  611. EFI_STATUS
  612. SetCapsuleStatusVariable (
  613. BOOLEAN SetCap
  614. )
  615. {
  616. EFI_STATUS Status;
  617. UINT64 OsIndication;
  618. UINTN DataSize;
  619. OsIndication = 0;
  620. DataSize = sizeof(UINT64);
  621. Status = gRT->GetVariable (
  622. L"OsIndications",
  623. &gEfiGlobalVariableGuid,
  624. NULL,
  625. &DataSize,
  626. &OsIndication
  627. );
  628. if (EFI_ERROR (Status)) {
  629. OsIndication = 0;
  630. }
  631. if (SetCap) {
  632. OsIndication |= ((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);
  633. }
  634. else {
  635. OsIndication &= ~((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);
  636. }
  637. Status = gRT->SetVariable (
  638. L"OsIndications",
  639. &gEfiGlobalVariableGuid,
  640. EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
  641. sizeof(UINT64),
  642. &OsIndication
  643. );
  644. return Status;
  645. }
  646. /**
  647. Process Capsule On Disk.
  648. @param[in] CapsuleBuffer An array of pointer to capsule images
  649. @param[in] CapsuleBufferSize An array of UINTN to capsule images size
  650. @param[in] FilePath An array of capsule images file path
  651. @param[in] Map File system mapping string
  652. @param[in] CapsuleNum The count of capsule images
  653. @retval EFI_SUCCESS Capsule on disk success.
  654. @retval others Capsule on disk fail.
  655. **/
  656. EFI_STATUS
  657. ProcessCapsuleOnDisk (
  658. IN VOID **CapsuleBuffer,
  659. IN UINTN *CapsuleBufferSize,
  660. IN CHAR16 **FilePath,
  661. IN CHAR16 *Map,
  662. IN UINTN CapsuleNum
  663. )
  664. {
  665. EFI_STATUS Status;
  666. UINT16 BootNext;
  667. EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
  668. BOOLEAN UpdateBootNext;
  669. //
  670. // Get a valid file system from boot path
  671. //
  672. Fs = NULL;
  673. Status = GetUpdateFileSystem (Map, &BootNext, &Fs, &UpdateBootNext);
  674. if (EFI_ERROR (Status)) {
  675. Print (L"CapsuleApp: cannot find a valid file system on boot devies. Status = %r\n", Status);
  676. return Status;
  677. }
  678. //
  679. // Copy capsule image to '\efi\UpdateCapsule\'
  680. //
  681. Status = WriteUpdateFile (CapsuleBuffer, CapsuleBufferSize, FilePath, CapsuleNum, Fs);
  682. if (EFI_ERROR (Status)) {
  683. Print (L"CapsuleApp: capsule image could not be copied for update.\n");
  684. return Status;
  685. }
  686. //
  687. // Set variable then reset
  688. //
  689. Status = SetCapsuleStatusVariable (TRUE);
  690. if (EFI_ERROR (Status)) {
  691. Print (L"CapsuleApp: unable to set OSIndication variable.\n");
  692. return Status;
  693. }
  694. if (UpdateBootNext) {
  695. Status = gRT->SetVariable (
  696. L"BootNext",
  697. &gEfiGlobalVariableGuid,
  698. EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
  699. sizeof(UINT16),
  700. &BootNext
  701. );
  702. if (EFI_ERROR (Status)){
  703. Print (L"CapsuleApp: unable to set BootNext variable.\n");
  704. return Status;
  705. }
  706. }
  707. return EFI_SUCCESS;
  708. }