QemuKernelLoaderFsDxe.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155
  1. /** @file
  2. DXE driver to expose the 'kernel', 'initrd' and 'cmdline' blobs
  3. provided by QEMU as files in an abstract file system
  4. Copyright (C) 2014-2016, Red Hat, Inc.
  5. Copyright (C) 2020, Arm, Limited.
  6. SPDX-License-Identifier: BSD-2-Clause-Patent
  7. **/
  8. #include <PiDxe.h>
  9. #include <Guid/FileInfo.h>
  10. #include <Guid/FileSystemInfo.h>
  11. #include <Guid/FileSystemVolumeLabelInfo.h>
  12. #include <Guid/LinuxEfiInitrdMedia.h>
  13. #include <Guid/QemuKernelLoaderFsMedia.h>
  14. #include <Library/BaseLib.h>
  15. #include <Library/BaseMemoryLib.h>
  16. #include <Library/BlobVerifierLib.h>
  17. #include <Library/DebugLib.h>
  18. #include <Library/DevicePathLib.h>
  19. #include <Library/MemoryAllocationLib.h>
  20. #include <Library/QemuFwCfgLib.h>
  21. #include <Library/UefiBootServicesTableLib.h>
  22. #include <Library/UefiRuntimeServicesTableLib.h>
  23. #include <Protocol/DevicePath.h>
  24. #include <Protocol/LoadFile2.h>
  25. #include <Protocol/SimpleFileSystem.h>
  26. //
  27. // Static data that hosts the fw_cfg blobs and serves file requests.
  28. //
  29. typedef enum {
  30. KernelBlobTypeKernel,
  31. KernelBlobTypeInitrd,
  32. KernelBlobTypeCommandLine,
  33. KernelBlobTypeMax
  34. } KERNEL_BLOB_TYPE;
  35. typedef struct {
  36. CONST CHAR16 Name[8];
  37. struct {
  38. FIRMWARE_CONFIG_ITEM CONST SizeKey;
  39. FIRMWARE_CONFIG_ITEM CONST DataKey;
  40. UINT32 Size;
  41. } FwCfgItem[2];
  42. UINT32 Size;
  43. UINT8 *Data;
  44. } KERNEL_BLOB;
  45. STATIC KERNEL_BLOB mKernelBlob[KernelBlobTypeMax] = {
  46. {
  47. L"kernel",
  48. {
  49. { QemuFwCfgItemKernelSetupSize, QemuFwCfgItemKernelSetupData, },
  50. { QemuFwCfgItemKernelSize, QemuFwCfgItemKernelData, },
  51. }
  52. }, {
  53. L"initrd",
  54. {
  55. { QemuFwCfgItemInitrdSize, QemuFwCfgItemInitrdData, },
  56. }
  57. }, {
  58. L"cmdline",
  59. {
  60. { QemuFwCfgItemCommandLineSize, QemuFwCfgItemCommandLineData, },
  61. }
  62. }
  63. };
  64. STATIC UINT64 mTotalBlobBytes;
  65. //
  66. // Device path for the handle that incorporates our "EFI stub filesystem".
  67. //
  68. #pragma pack (1)
  69. typedef struct {
  70. VENDOR_DEVICE_PATH VenMediaNode;
  71. EFI_DEVICE_PATH_PROTOCOL EndNode;
  72. } SINGLE_VENMEDIA_NODE_DEVPATH;
  73. #pragma pack ()
  74. STATIC CONST SINGLE_VENMEDIA_NODE_DEVPATH mFileSystemDevicePath = {
  75. {
  76. {
  77. MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,
  78. { sizeof (VENDOR_DEVICE_PATH) }
  79. },
  80. QEMU_KERNEL_LOADER_FS_MEDIA_GUID
  81. }, {
  82. END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
  83. { sizeof (EFI_DEVICE_PATH_PROTOCOL) }
  84. }
  85. };
  86. STATIC CONST SINGLE_VENMEDIA_NODE_DEVPATH mInitrdDevicePath = {
  87. {
  88. {
  89. MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,
  90. { sizeof (VENDOR_DEVICE_PATH) }
  91. },
  92. LINUX_EFI_INITRD_MEDIA_GUID
  93. }, {
  94. END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
  95. { sizeof (EFI_DEVICE_PATH_PROTOCOL) }
  96. }
  97. };
  98. //
  99. // The "file in the EFI stub filesystem" abstraction.
  100. //
  101. STATIC EFI_TIME mInitTime;
  102. #define STUB_FILE_SIG SIGNATURE_64 ('S', 'T', 'U', 'B', 'F', 'I', 'L', 'E')
  103. typedef struct {
  104. UINT64 Signature; // Carries STUB_FILE_SIG.
  105. KERNEL_BLOB_TYPE BlobType; // Index into mKernelBlob. KernelBlobTypeMax
  106. // denotes the root directory of the filesystem.
  107. UINT64 Position; // Byte position for regular files;
  108. // next directory entry to return for the root
  109. // directory.
  110. EFI_FILE_PROTOCOL File; // Standard protocol interface.
  111. } STUB_FILE;
  112. #define STUB_FILE_FROM_FILE(FilePointer) \
  113. CR (FilePointer, STUB_FILE, File, STUB_FILE_SIG)
  114. //
  115. // Protocol member functions for File.
  116. //
  117. /**
  118. Opens a new file relative to the source file's location.
  119. (Forward declaration.)
  120. @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
  121. the file handle to the source location. This would
  122. typically be an open handle to a directory.
  123. @param[out] NewHandle A pointer to the location to return the opened handle
  124. for the new file.
  125. @param[in] FileName The Null-terminated string of the name of the file to
  126. be opened. The file name may contain the following
  127. path modifiers: "\", ".", and "..".
  128. @param[in] OpenMode The mode to open the file. The only valid
  129. combinations that the file may be opened with are:
  130. Read, Read/Write, or Create/Read/Write.
  131. @param[in] Attributes Only valid for EFI_FILE_MODE_CREATE, in which case
  132. these are the attribute bits for the newly created
  133. file.
  134. @retval EFI_SUCCESS The file was opened.
  135. @retval EFI_NOT_FOUND The specified file could not be found on the
  136. device.
  137. @retval EFI_NO_MEDIA The device has no medium.
  138. @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
  139. medium is no longer supported.
  140. @retval EFI_DEVICE_ERROR The device reported an error.
  141. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
  142. @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a
  143. file for write when the media is
  144. write-protected.
  145. @retval EFI_ACCESS_DENIED The service denied access to the file.
  146. @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
  147. file.
  148. @retval EFI_VOLUME_FULL The volume is full.
  149. **/
  150. STATIC
  151. EFI_STATUS
  152. EFIAPI
  153. StubFileOpen (
  154. IN EFI_FILE_PROTOCOL *This,
  155. OUT EFI_FILE_PROTOCOL **NewHandle,
  156. IN CHAR16 *FileName,
  157. IN UINT64 OpenMode,
  158. IN UINT64 Attributes
  159. );
  160. /**
  161. Closes a specified file handle.
  162. @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file
  163. handle to close.
  164. @retval EFI_SUCCESS The file was closed.
  165. **/
  166. STATIC
  167. EFI_STATUS
  168. EFIAPI
  169. StubFileClose (
  170. IN EFI_FILE_PROTOCOL *This
  171. )
  172. {
  173. FreePool (STUB_FILE_FROM_FILE (This));
  174. return EFI_SUCCESS;
  175. }
  176. /**
  177. Close and delete the file handle.
  178. @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
  179. handle to the file to delete.
  180. @retval EFI_SUCCESS The file was closed and deleted, and the
  181. handle was closed.
  182. @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not
  183. deleted.
  184. **/
  185. STATIC
  186. EFI_STATUS
  187. EFIAPI
  188. StubFileDelete (
  189. IN EFI_FILE_PROTOCOL *This
  190. )
  191. {
  192. FreePool (STUB_FILE_FROM_FILE (This));
  193. return EFI_WARN_DELETE_FAILURE;
  194. }
  195. /**
  196. Helper function that formats an EFI_FILE_INFO structure into the
  197. user-allocated buffer, for any valid KERNEL_BLOB_TYPE value (including
  198. KernelBlobTypeMax, which stands for the root directory).
  199. The interface follows the EFI_FILE_GET_INFO -- and for directories, the
  200. EFI_FILE_READ -- interfaces.
  201. @param[in] BlobType The KERNEL_BLOB_TYPE value identifying the fw_cfg
  202. blob backing the STUB_FILE that information is
  203. being requested about. If BlobType equals
  204. KernelBlobTypeMax, then information will be
  205. provided about the root directory of the
  206. filesystem.
  207. @param[in,out] BufferSize On input, the size of Buffer. On output, the
  208. amount of data returned in Buffer. In both cases,
  209. the size is measured in bytes.
  210. @param[out] Buffer A pointer to the data buffer to return. The
  211. buffer's type is EFI_FILE_INFO.
  212. @retval EFI_SUCCESS The information was returned.
  213. @retval EFI_BUFFER_TOO_SMALL BufferSize is too small to store the
  214. EFI_FILE_INFO structure. BufferSize has been
  215. updated with the size needed to complete the
  216. request.
  217. **/
  218. STATIC
  219. EFI_STATUS
  220. ConvertKernelBlobTypeToFileInfo (
  221. IN KERNEL_BLOB_TYPE BlobType,
  222. IN OUT UINTN *BufferSize,
  223. OUT VOID *Buffer
  224. )
  225. {
  226. CONST CHAR16 *Name;
  227. UINT64 FileSize;
  228. UINT64 Attribute;
  229. UINTN NameSize;
  230. UINTN FileInfoSize;
  231. EFI_FILE_INFO *FileInfo;
  232. UINTN OriginalBufferSize;
  233. if (BlobType == KernelBlobTypeMax) {
  234. //
  235. // getting file info about the root directory
  236. //
  237. Name = L"\\";
  238. FileSize = KernelBlobTypeMax;
  239. Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;
  240. } else {
  241. CONST KERNEL_BLOB *Blob;
  242. Blob = &mKernelBlob[BlobType];
  243. Name = Blob->Name;
  244. FileSize = Blob->Size;
  245. Attribute = EFI_FILE_READ_ONLY;
  246. }
  247. NameSize = (StrLen (Name) + 1) * 2;
  248. FileInfoSize = OFFSET_OF (EFI_FILE_INFO, FileName) + NameSize;
  249. ASSERT (FileInfoSize >= sizeof *FileInfo);
  250. OriginalBufferSize = *BufferSize;
  251. *BufferSize = FileInfoSize;
  252. if (OriginalBufferSize < *BufferSize) {
  253. return EFI_BUFFER_TOO_SMALL;
  254. }
  255. FileInfo = (EFI_FILE_INFO *)Buffer;
  256. FileInfo->Size = FileInfoSize;
  257. FileInfo->FileSize = FileSize;
  258. FileInfo->PhysicalSize = FileSize;
  259. FileInfo->Attribute = Attribute;
  260. CopyMem (&FileInfo->CreateTime, &mInitTime, sizeof mInitTime);
  261. CopyMem (&FileInfo->LastAccessTime, &mInitTime, sizeof mInitTime);
  262. CopyMem (&FileInfo->ModificationTime, &mInitTime, sizeof mInitTime);
  263. CopyMem (FileInfo->FileName, Name, NameSize);
  264. return EFI_SUCCESS;
  265. }
  266. /**
  267. Reads data from a file, or continues scanning a directory.
  268. @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
  269. is the file handle to read data from.
  270. @param[in,out] BufferSize On input, the size of the Buffer. On output, the
  271. amount of data returned in Buffer. In both cases,
  272. the size is measured in bytes. If the read goes
  273. beyond the end of the file, the read length is
  274. truncated to the end of the file.
  275. If This is a directory, the function reads the
  276. directory entry at the current position and
  277. returns the entry (as EFI_FILE_INFO) in Buffer. If
  278. there are no more directory entries, the
  279. BufferSize is set to zero on output.
  280. @param[out] Buffer The buffer into which the data is read.
  281. @retval EFI_SUCCESS Data was read.
  282. @retval EFI_NO_MEDIA The device has no medium.
  283. @retval EFI_DEVICE_ERROR The device reported an error.
  284. @retval EFI_DEVICE_ERROR An attempt was made to read from a deleted
  285. file.
  286. @retval EFI_DEVICE_ERROR On entry, the current file position is beyond
  287. the end of the file.
  288. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
  289. @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to store the
  290. current directory entry as a EFI_FILE_INFO
  291. structure. BufferSize has been updated with the
  292. size needed to complete the request, and the
  293. directory position has not been advanced.
  294. **/
  295. STATIC
  296. EFI_STATUS
  297. EFIAPI
  298. StubFileRead (
  299. IN EFI_FILE_PROTOCOL *This,
  300. IN OUT UINTN *BufferSize,
  301. OUT VOID *Buffer
  302. )
  303. {
  304. STUB_FILE *StubFile;
  305. CONST KERNEL_BLOB *Blob;
  306. UINT64 Left;
  307. StubFile = STUB_FILE_FROM_FILE (This);
  308. //
  309. // Scanning the root directory?
  310. //
  311. if (StubFile->BlobType == KernelBlobTypeMax) {
  312. EFI_STATUS Status;
  313. if (StubFile->Position == KernelBlobTypeMax) {
  314. //
  315. // Scanning complete.
  316. //
  317. *BufferSize = 0;
  318. return EFI_SUCCESS;
  319. }
  320. Status = ConvertKernelBlobTypeToFileInfo (
  321. (KERNEL_BLOB_TYPE)StubFile->Position,
  322. BufferSize,
  323. Buffer
  324. );
  325. if (EFI_ERROR (Status)) {
  326. return Status;
  327. }
  328. ++StubFile->Position;
  329. return EFI_SUCCESS;
  330. }
  331. //
  332. // Reading a file.
  333. //
  334. Blob = &mKernelBlob[StubFile->BlobType];
  335. if (StubFile->Position > Blob->Size) {
  336. return EFI_DEVICE_ERROR;
  337. }
  338. Left = Blob->Size - StubFile->Position;
  339. if (*BufferSize > Left) {
  340. *BufferSize = (UINTN)Left;
  341. }
  342. if (Blob->Data != NULL) {
  343. CopyMem (Buffer, Blob->Data + StubFile->Position, *BufferSize);
  344. }
  345. StubFile->Position += *BufferSize;
  346. return EFI_SUCCESS;
  347. }
  348. /**
  349. Writes data to a file.
  350. @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
  351. is the file handle to write data to.
  352. @param[in,out] BufferSize On input, the size of the Buffer. On output, the
  353. amount of data actually written. In both cases,
  354. the size is measured in bytes.
  355. @param[in] Buffer The buffer of data to write.
  356. @retval EFI_SUCCESS Data was written.
  357. @retval EFI_UNSUPPORTED Writes to open directory files are not
  358. supported.
  359. @retval EFI_NO_MEDIA The device has no medium.
  360. @retval EFI_DEVICE_ERROR The device reported an error.
  361. @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
  362. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
  363. @retval EFI_WRITE_PROTECTED The file or medium is write-protected.
  364. @retval EFI_ACCESS_DENIED The file was opened read only.
  365. @retval EFI_VOLUME_FULL The volume is full.
  366. **/
  367. STATIC
  368. EFI_STATUS
  369. EFIAPI
  370. StubFileWrite (
  371. IN EFI_FILE_PROTOCOL *This,
  372. IN OUT UINTN *BufferSize,
  373. IN VOID *Buffer
  374. )
  375. {
  376. STUB_FILE *StubFile;
  377. StubFile = STUB_FILE_FROM_FILE (This);
  378. return (StubFile->BlobType == KernelBlobTypeMax) ?
  379. EFI_UNSUPPORTED :
  380. EFI_WRITE_PROTECTED;
  381. }
  382. /**
  383. Returns a file's current position.
  384. @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
  385. file handle to get the current position on.
  386. @param[out] Position The address to return the file's current position
  387. value.
  388. @retval EFI_SUCCESS The position was returned.
  389. @retval EFI_UNSUPPORTED The request is not valid on open directories.
  390. @retval EFI_DEVICE_ERROR An attempt was made to get the position from a
  391. deleted file.
  392. **/
  393. STATIC
  394. EFI_STATUS
  395. EFIAPI
  396. StubFileGetPosition (
  397. IN EFI_FILE_PROTOCOL *This,
  398. OUT UINT64 *Position
  399. )
  400. {
  401. STUB_FILE *StubFile;
  402. StubFile = STUB_FILE_FROM_FILE (This);
  403. if (StubFile->BlobType == KernelBlobTypeMax) {
  404. return EFI_UNSUPPORTED;
  405. }
  406. *Position = StubFile->Position;
  407. return EFI_SUCCESS;
  408. }
  409. /**
  410. Sets a file's current position.
  411. @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
  412. file handle to set the requested position on.
  413. @param[in] Position The byte position from the start of the file to set. For
  414. regular files, MAX_UINT64 means "seek to end". For
  415. directories, zero means "rewind directory scan".
  416. @retval EFI_SUCCESS The position was set.
  417. @retval EFI_UNSUPPORTED The seek request for nonzero is not valid on open
  418. directories.
  419. @retval EFI_DEVICE_ERROR An attempt was made to set the position of a
  420. deleted file.
  421. **/
  422. STATIC
  423. EFI_STATUS
  424. EFIAPI
  425. StubFileSetPosition (
  426. IN EFI_FILE_PROTOCOL *This,
  427. IN UINT64 Position
  428. )
  429. {
  430. STUB_FILE *StubFile;
  431. KERNEL_BLOB *Blob;
  432. StubFile = STUB_FILE_FROM_FILE (This);
  433. if (StubFile->BlobType == KernelBlobTypeMax) {
  434. if (Position == 0) {
  435. //
  436. // rewinding a directory scan is allowed
  437. //
  438. StubFile->Position = 0;
  439. return EFI_SUCCESS;
  440. }
  441. return EFI_UNSUPPORTED;
  442. }
  443. //
  444. // regular file seek
  445. //
  446. Blob = &mKernelBlob[StubFile->BlobType];
  447. if (Position == MAX_UINT64) {
  448. //
  449. // seek to end
  450. //
  451. StubFile->Position = Blob->Size;
  452. } else {
  453. //
  454. // absolute seek from beginning -- seeking past the end is allowed
  455. //
  456. StubFile->Position = Position;
  457. }
  458. return EFI_SUCCESS;
  459. }
  460. /**
  461. Returns information about a file.
  462. @param[in] This A pointer to the EFI_FILE_PROTOCOL instance
  463. that is the file handle the requested
  464. information is for.
  465. @param[in] InformationType The type identifier GUID for the information
  466. being requested. The following information
  467. types are supported, storing the
  468. corresponding structures in Buffer:
  469. - gEfiFileInfoGuid: EFI_FILE_INFO
  470. - gEfiFileSystemInfoGuid:
  471. EFI_FILE_SYSTEM_INFO
  472. - gEfiFileSystemVolumeLabelInfoIdGuid:
  473. EFI_FILE_SYSTEM_VOLUME_LABEL
  474. @param[in,out] BufferSize On input, the size of Buffer. On output, the
  475. amount of data returned in Buffer. In both
  476. cases, the size is measured in bytes.
  477. @param[out] Buffer A pointer to the data buffer to return. The
  478. buffer's type is indicated by
  479. InformationType.
  480. @retval EFI_SUCCESS The information was returned.
  481. @retval EFI_UNSUPPORTED The InformationType is not known.
  482. @retval EFI_NO_MEDIA The device has no medium.
  483. @retval EFI_DEVICE_ERROR The device reported an error.
  484. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
  485. @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to store the
  486. information structure requested by
  487. InformationType. BufferSize has been updated
  488. with the size needed to complete the request.
  489. **/
  490. STATIC
  491. EFI_STATUS
  492. EFIAPI
  493. StubFileGetInfo (
  494. IN EFI_FILE_PROTOCOL *This,
  495. IN EFI_GUID *InformationType,
  496. IN OUT UINTN *BufferSize,
  497. OUT VOID *Buffer
  498. )
  499. {
  500. CONST STUB_FILE *StubFile;
  501. UINTN OriginalBufferSize;
  502. StubFile = STUB_FILE_FROM_FILE (This);
  503. if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
  504. return ConvertKernelBlobTypeToFileInfo (
  505. StubFile->BlobType,
  506. BufferSize,
  507. Buffer
  508. );
  509. }
  510. OriginalBufferSize = *BufferSize;
  511. if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
  512. EFI_FILE_SYSTEM_INFO *FileSystemInfo;
  513. *BufferSize = sizeof *FileSystemInfo;
  514. if (OriginalBufferSize < *BufferSize) {
  515. return EFI_BUFFER_TOO_SMALL;
  516. }
  517. FileSystemInfo = (EFI_FILE_SYSTEM_INFO *)Buffer;
  518. FileSystemInfo->Size = sizeof *FileSystemInfo;
  519. FileSystemInfo->ReadOnly = TRUE;
  520. FileSystemInfo->VolumeSize = mTotalBlobBytes;
  521. FileSystemInfo->FreeSpace = 0;
  522. FileSystemInfo->BlockSize = 1;
  523. FileSystemInfo->VolumeLabel[0] = L'\0';
  524. return EFI_SUCCESS;
  525. }
  526. if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
  527. EFI_FILE_SYSTEM_VOLUME_LABEL *FileSystemVolumeLabel;
  528. *BufferSize = sizeof *FileSystemVolumeLabel;
  529. if (OriginalBufferSize < *BufferSize) {
  530. return EFI_BUFFER_TOO_SMALL;
  531. }
  532. FileSystemVolumeLabel = (EFI_FILE_SYSTEM_VOLUME_LABEL *)Buffer;
  533. FileSystemVolumeLabel->VolumeLabel[0] = L'\0';
  534. return EFI_SUCCESS;
  535. }
  536. return EFI_UNSUPPORTED;
  537. }
  538. /**
  539. Sets information about a file.
  540. @param[in] File A pointer to the EFI_FILE_PROTOCOL instance that
  541. is the file handle the information is for.
  542. @param[in] InformationType The type identifier for the information being
  543. set.
  544. @param[in] BufferSize The size, in bytes, of Buffer.
  545. @param[in] Buffer A pointer to the data buffer to write. The
  546. buffer's type is indicated by InformationType.
  547. @retval EFI_SUCCESS The information was set.
  548. @retval EFI_UNSUPPORTED The InformationType is not known.
  549. @retval EFI_NO_MEDIA The device has no medium.
  550. @retval EFI_DEVICE_ERROR The device reported an error.
  551. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
  552. @retval EFI_WRITE_PROTECTED InformationType is EFI_FILE_INFO_ID and the
  553. media is read-only.
  554. @retval EFI_WRITE_PROTECTED InformationType is
  555. EFI_FILE_PROTOCOL_SYSTEM_INFO_ID and the media
  556. is read only.
  557. @retval EFI_WRITE_PROTECTED InformationType is
  558. EFI_FILE_SYSTEM_VOLUME_LABEL_ID and the media
  559. is read-only.
  560. @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
  561. to a file that is already present.
  562. @retval EFI_ACCESS_DENIED An attempt is being made to change the
  563. EFI_FILE_DIRECTORY Attribute.
  564. @retval EFI_ACCESS_DENIED An attempt is being made to change the size of
  565. a directory.
  566. @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and the
  567. file was opened read-only and an attempt is
  568. being made to modify a field other than
  569. Attribute.
  570. @retval EFI_VOLUME_FULL The volume is full.
  571. @retval EFI_BAD_BUFFER_SIZE BufferSize is smaller than the size of the type
  572. indicated by InformationType.
  573. **/
  574. STATIC
  575. EFI_STATUS
  576. EFIAPI
  577. StubFileSetInfo (
  578. IN EFI_FILE_PROTOCOL *This,
  579. IN EFI_GUID *InformationType,
  580. IN UINTN BufferSize,
  581. IN VOID *Buffer
  582. )
  583. {
  584. return EFI_WRITE_PROTECTED;
  585. }
  586. /**
  587. Flushes all modified data associated with a file to a device.
  588. @param [in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
  589. file handle to flush.
  590. @retval EFI_SUCCESS The data was flushed.
  591. @retval EFI_NO_MEDIA The device has no medium.
  592. @retval EFI_DEVICE_ERROR The device reported an error.
  593. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
  594. @retval EFI_WRITE_PROTECTED The file or medium is write-protected.
  595. @retval EFI_ACCESS_DENIED The file was opened read-only.
  596. @retval EFI_VOLUME_FULL The volume is full.
  597. **/
  598. STATIC
  599. EFI_STATUS
  600. EFIAPI
  601. StubFileFlush (
  602. IN EFI_FILE_PROTOCOL *This
  603. )
  604. {
  605. return EFI_WRITE_PROTECTED;
  606. }
  607. //
  608. // External definition of the file protocol template.
  609. //
  610. STATIC CONST EFI_FILE_PROTOCOL mEfiFileProtocolTemplate = {
  611. EFI_FILE_PROTOCOL_REVISION, // revision 1
  612. StubFileOpen,
  613. StubFileClose,
  614. StubFileDelete,
  615. StubFileRead,
  616. StubFileWrite,
  617. StubFileGetPosition,
  618. StubFileSetPosition,
  619. StubFileGetInfo,
  620. StubFileSetInfo,
  621. StubFileFlush,
  622. NULL, // OpenEx, revision 2
  623. NULL, // ReadEx, revision 2
  624. NULL, // WriteEx, revision 2
  625. NULL // FlushEx, revision 2
  626. };
  627. STATIC
  628. EFI_STATUS
  629. EFIAPI
  630. StubFileOpen (
  631. IN EFI_FILE_PROTOCOL *This,
  632. OUT EFI_FILE_PROTOCOL **NewHandle,
  633. IN CHAR16 *FileName,
  634. IN UINT64 OpenMode,
  635. IN UINT64 Attributes
  636. )
  637. {
  638. CONST STUB_FILE *StubFile;
  639. UINTN BlobType;
  640. STUB_FILE *NewStubFile;
  641. //
  642. // We're read-only.
  643. //
  644. switch (OpenMode) {
  645. case EFI_FILE_MODE_READ:
  646. break;
  647. case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE:
  648. case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE:
  649. return EFI_WRITE_PROTECTED;
  650. default:
  651. return EFI_INVALID_PARAMETER;
  652. }
  653. //
  654. // Only the root directory supports opening files in it.
  655. //
  656. StubFile = STUB_FILE_FROM_FILE (This);
  657. if (StubFile->BlobType != KernelBlobTypeMax) {
  658. return EFI_UNSUPPORTED;
  659. }
  660. //
  661. // Locate the file.
  662. //
  663. for (BlobType = 0; BlobType < KernelBlobTypeMax; ++BlobType) {
  664. if (StrCmp (FileName, mKernelBlob[BlobType].Name) == 0) {
  665. break;
  666. }
  667. }
  668. if (BlobType == KernelBlobTypeMax) {
  669. return EFI_NOT_FOUND;
  670. }
  671. //
  672. // Found it.
  673. //
  674. NewStubFile = AllocatePool (sizeof *NewStubFile);
  675. if (NewStubFile == NULL) {
  676. return EFI_OUT_OF_RESOURCES;
  677. }
  678. NewStubFile->Signature = STUB_FILE_SIG;
  679. NewStubFile->BlobType = (KERNEL_BLOB_TYPE)BlobType;
  680. NewStubFile->Position = 0;
  681. CopyMem (
  682. &NewStubFile->File,
  683. &mEfiFileProtocolTemplate,
  684. sizeof mEfiFileProtocolTemplate
  685. );
  686. *NewHandle = &NewStubFile->File;
  687. return EFI_SUCCESS;
  688. }
  689. //
  690. // Protocol member functions for SimpleFileSystem.
  691. //
  692. /**
  693. Open the root directory on a volume.
  694. @param[in] This A pointer to the volume to open the root directory on.
  695. @param[out] Root A pointer to the location to return the opened file handle
  696. for the root directory in.
  697. @retval EFI_SUCCESS The device was opened.
  698. @retval EFI_UNSUPPORTED This volume does not support the requested file
  699. system type.
  700. @retval EFI_NO_MEDIA The device has no medium.
  701. @retval EFI_DEVICE_ERROR The device reported an error.
  702. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
  703. @retval EFI_ACCESS_DENIED The service denied access to the file.
  704. @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of
  705. resources.
  706. @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
  707. medium is no longer supported. Any existing
  708. file handles for this volume are no longer
  709. valid. To access the files on the new medium,
  710. the volume must be reopened with OpenVolume().
  711. **/
  712. STATIC
  713. EFI_STATUS
  714. EFIAPI
  715. StubFileSystemOpenVolume (
  716. IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
  717. OUT EFI_FILE_PROTOCOL **Root
  718. )
  719. {
  720. STUB_FILE *StubFile;
  721. StubFile = AllocatePool (sizeof *StubFile);
  722. if (StubFile == NULL) {
  723. return EFI_OUT_OF_RESOURCES;
  724. }
  725. StubFile->Signature = STUB_FILE_SIG;
  726. StubFile->BlobType = KernelBlobTypeMax;
  727. StubFile->Position = 0;
  728. CopyMem (
  729. &StubFile->File,
  730. &mEfiFileProtocolTemplate,
  731. sizeof mEfiFileProtocolTemplate
  732. );
  733. *Root = &StubFile->File;
  734. return EFI_SUCCESS;
  735. }
  736. STATIC CONST EFI_SIMPLE_FILE_SYSTEM_PROTOCOL mFileSystem = {
  737. EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
  738. StubFileSystemOpenVolume
  739. };
  740. STATIC
  741. EFI_STATUS
  742. EFIAPI
  743. InitrdLoadFile2 (
  744. IN EFI_LOAD_FILE2_PROTOCOL *This,
  745. IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
  746. IN BOOLEAN BootPolicy,
  747. IN OUT UINTN *BufferSize,
  748. OUT VOID *Buffer OPTIONAL
  749. )
  750. {
  751. CONST KERNEL_BLOB *InitrdBlob = &mKernelBlob[KernelBlobTypeInitrd];
  752. ASSERT (InitrdBlob->Size > 0);
  753. if (BootPolicy) {
  754. return EFI_UNSUPPORTED;
  755. }
  756. if ((BufferSize == NULL) || !IsDevicePathValid (FilePath, 0)) {
  757. return EFI_INVALID_PARAMETER;
  758. }
  759. if ((FilePath->Type != END_DEVICE_PATH_TYPE) ||
  760. (FilePath->SubType != END_ENTIRE_DEVICE_PATH_SUBTYPE))
  761. {
  762. return EFI_NOT_FOUND;
  763. }
  764. if ((Buffer == NULL) || (*BufferSize < InitrdBlob->Size)) {
  765. *BufferSize = InitrdBlob->Size;
  766. return EFI_BUFFER_TOO_SMALL;
  767. }
  768. CopyMem (Buffer, InitrdBlob->Data, InitrdBlob->Size);
  769. *BufferSize = InitrdBlob->Size;
  770. return EFI_SUCCESS;
  771. }
  772. STATIC CONST EFI_LOAD_FILE2_PROTOCOL mInitrdLoadFile2 = {
  773. InitrdLoadFile2,
  774. };
  775. //
  776. // Utility functions.
  777. //
  778. /**
  779. Populate a blob in mKernelBlob.
  780. param[in,out] Blob Pointer to the KERNEL_BLOB element in mKernelBlob that is
  781. to be filled from fw_cfg.
  782. @retval EFI_SUCCESS Blob has been populated. If fw_cfg reported a
  783. size of zero for the blob, then Blob->Data has
  784. been left unchanged.
  785. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for Blob->Data.
  786. **/
  787. STATIC
  788. EFI_STATUS
  789. FetchBlob (
  790. IN OUT KERNEL_BLOB *Blob
  791. )
  792. {
  793. UINT32 Left;
  794. UINTN Idx;
  795. UINT8 *ChunkData;
  796. //
  797. // Read blob size.
  798. //
  799. Blob->Size = 0;
  800. for (Idx = 0; Idx < ARRAY_SIZE (Blob->FwCfgItem); Idx++) {
  801. if (Blob->FwCfgItem[Idx].SizeKey == 0) {
  802. break;
  803. }
  804. QemuFwCfgSelectItem (Blob->FwCfgItem[Idx].SizeKey);
  805. Blob->FwCfgItem[Idx].Size = QemuFwCfgRead32 ();
  806. Blob->Size += Blob->FwCfgItem[Idx].Size;
  807. }
  808. if (Blob->Size == 0) {
  809. return EFI_SUCCESS;
  810. }
  811. //
  812. // Read blob.
  813. //
  814. Blob->Data = AllocatePool (Blob->Size);
  815. if (Blob->Data == NULL) {
  816. DEBUG ((
  817. DEBUG_ERROR,
  818. "%a: failed to allocate %Ld bytes for \"%s\"\n",
  819. __FUNCTION__,
  820. (INT64)Blob->Size,
  821. Blob->Name
  822. ));
  823. return EFI_OUT_OF_RESOURCES;
  824. }
  825. DEBUG ((
  826. DEBUG_INFO,
  827. "%a: loading %Ld bytes for \"%s\"\n",
  828. __FUNCTION__,
  829. (INT64)Blob->Size,
  830. Blob->Name
  831. ));
  832. ChunkData = Blob->Data;
  833. for (Idx = 0; Idx < ARRAY_SIZE (Blob->FwCfgItem); Idx++) {
  834. if (Blob->FwCfgItem[Idx].DataKey == 0) {
  835. break;
  836. }
  837. QemuFwCfgSelectItem (Blob->FwCfgItem[Idx].DataKey);
  838. Left = Blob->FwCfgItem[Idx].Size;
  839. while (Left > 0) {
  840. UINT32 Chunk;
  841. Chunk = (Left < SIZE_1MB) ? Left : SIZE_1MB;
  842. QemuFwCfgReadBytes (Chunk, ChunkData + Blob->FwCfgItem[Idx].Size - Left);
  843. Left -= Chunk;
  844. DEBUG ((
  845. DEBUG_VERBOSE,
  846. "%a: %Ld bytes remaining for \"%s\" (%d)\n",
  847. __FUNCTION__,
  848. (INT64)Left,
  849. Blob->Name,
  850. (INT32)Idx
  851. ));
  852. }
  853. ChunkData += Blob->FwCfgItem[Idx].Size;
  854. }
  855. return EFI_SUCCESS;
  856. }
  857. //
  858. // The entry point of the feature.
  859. //
  860. /**
  861. Download the kernel, the initial ramdisk, and the kernel command line from
  862. QEMU's fw_cfg. Construct a minimal SimpleFileSystem that contains the two
  863. image files.
  864. @retval EFI_NOT_FOUND Kernel image was not found.
  865. @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
  866. @retval EFI_PROTOCOL_ERROR Unterminated kernel command line.
  867. @return Error codes from any of the underlying
  868. functions. On success, the function doesn't
  869. return.
  870. **/
  871. EFI_STATUS
  872. EFIAPI
  873. QemuKernelLoaderFsDxeEntrypoint (
  874. IN EFI_HANDLE ImageHandle,
  875. IN EFI_SYSTEM_TABLE *SystemTable
  876. )
  877. {
  878. UINTN BlobType;
  879. KERNEL_BLOB *CurrentBlob;
  880. KERNEL_BLOB *KernelBlob;
  881. EFI_STATUS Status;
  882. EFI_HANDLE FileSystemHandle;
  883. EFI_HANDLE InitrdLoadFile2Handle;
  884. if (!QemuFwCfgIsAvailable ()) {
  885. return EFI_NOT_FOUND;
  886. }
  887. Status = gRT->GetTime (&mInitTime, NULL /* Capabilities */);
  888. if (EFI_ERROR (Status)) {
  889. DEBUG ((DEBUG_ERROR, "%a: GetTime(): %r\n", __FUNCTION__, Status));
  890. return Status;
  891. }
  892. //
  893. // Fetch all blobs.
  894. //
  895. for (BlobType = 0; BlobType < KernelBlobTypeMax; ++BlobType) {
  896. CurrentBlob = &mKernelBlob[BlobType];
  897. Status = FetchBlob (CurrentBlob);
  898. if (EFI_ERROR (Status)) {
  899. goto FreeBlobs;
  900. }
  901. Status = VerifyBlob (
  902. CurrentBlob->Name,
  903. CurrentBlob->Data,
  904. CurrentBlob->Size
  905. );
  906. if (EFI_ERROR (Status)) {
  907. goto FreeBlobs;
  908. }
  909. mTotalBlobBytes += CurrentBlob->Size;
  910. }
  911. KernelBlob = &mKernelBlob[KernelBlobTypeKernel];
  912. if (KernelBlob->Data == NULL) {
  913. Status = EFI_NOT_FOUND;
  914. goto FreeBlobs;
  915. }
  916. //
  917. // Create a new handle with a single VenMedia() node device path protocol on
  918. // it, plus a custom SimpleFileSystem protocol on it.
  919. //
  920. FileSystemHandle = NULL;
  921. Status = gBS->InstallMultipleProtocolInterfaces (
  922. &FileSystemHandle,
  923. &gEfiDevicePathProtocolGuid,
  924. &mFileSystemDevicePath,
  925. &gEfiSimpleFileSystemProtocolGuid,
  926. &mFileSystem,
  927. NULL
  928. );
  929. if (EFI_ERROR (Status)) {
  930. DEBUG ((
  931. DEBUG_ERROR,
  932. "%a: InstallMultipleProtocolInterfaces(): %r\n",
  933. __FUNCTION__,
  934. Status
  935. ));
  936. goto FreeBlobs;
  937. }
  938. if (KernelBlob[KernelBlobTypeInitrd].Size > 0) {
  939. InitrdLoadFile2Handle = NULL;
  940. Status = gBS->InstallMultipleProtocolInterfaces (
  941. &InitrdLoadFile2Handle,
  942. &gEfiDevicePathProtocolGuid,
  943. &mInitrdDevicePath,
  944. &gEfiLoadFile2ProtocolGuid,
  945. &mInitrdLoadFile2,
  946. NULL
  947. );
  948. if (EFI_ERROR (Status)) {
  949. DEBUG ((
  950. DEBUG_ERROR,
  951. "%a: InstallMultipleProtocolInterfaces(): %r\n",
  952. __FUNCTION__,
  953. Status
  954. ));
  955. goto UninstallFileSystemHandle;
  956. }
  957. }
  958. return EFI_SUCCESS;
  959. UninstallFileSystemHandle:
  960. Status = gBS->UninstallMultipleProtocolInterfaces (
  961. FileSystemHandle,
  962. &gEfiDevicePathProtocolGuid,
  963. &mFileSystemDevicePath,
  964. &gEfiSimpleFileSystemProtocolGuid,
  965. &mFileSystem,
  966. NULL
  967. );
  968. ASSERT_EFI_ERROR (Status);
  969. FreeBlobs:
  970. while (BlobType > 0) {
  971. CurrentBlob = &mKernelBlob[--BlobType];
  972. if (CurrentBlob->Data != NULL) {
  973. FreePool (CurrentBlob->Data);
  974. CurrentBlob->Size = 0;
  975. CurrentBlob->Data = NULL;
  976. }
  977. }
  978. return Status;
  979. }