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