TianoCore EDK2 master
Loading...
Searching...
No Matches
Helpers.c
Go to the documentation of this file.
1
9#include <Library/BaseLib.h> // StrLen()
10#include <Library/BaseMemoryLib.h> // CopyMem()
11#include <Library/MemoryAllocationLib.h> // AllocatePool()
12#include <Library/TimeBaseLib.h> // EpochToEfiTime()
13#include <Library/VirtioLib.h> // Virtio10WriteFeatures()
14
15#include "VirtioFsDxe.h"
16
33 OUT VIRTIO_FS_CONFIG *Config
34 )
35{
36 UINTN Idx;
37 EFI_STATUS Status;
38
39 for (Idx = 0; Idx < VIRTIO_FS_TAG_BYTES; Idx++) {
40 Status = Virtio->ReadDevice (
41 Virtio, // This
42 OFFSET_OF (VIRTIO_FS_CONFIG, Tag[Idx]), // FieldOffset
43 sizeof Config->Tag[Idx], // FieldSize
44 sizeof Config->Tag[Idx], // BufferSize
45 &Config->Tag[Idx] // Buffer
46 );
47 if (EFI_ERROR (Status)) {
48 return Status;
49 }
50 }
51
52 Status = Virtio->ReadDevice (
53 Virtio, // This
54 OFFSET_OF (VIRTIO_FS_CONFIG, NumReqQueues), // FieldOffset
55 sizeof Config->NumReqQueues, // FieldSize
56 sizeof Config->NumReqQueues, // BufferSize
57 &Config->NumReqQueues // Buffer
58 );
59 return Status;
60}
61
81 IN OUT VIRTIO_FS *VirtioFs
82 )
83{
84 UINT8 NextDevStat;
85 EFI_STATUS Status;
86 UINT64 Features;
87 VIRTIO_FS_CONFIG Config;
88 UINTN Idx;
89 UINT64 RingBaseShift;
90
91 //
92 // Execute virtio-v1.1-cs01-87fa6b5d8155, 3.1.1 Driver Requirements: Device
93 // Initialization.
94 //
95 // 1. Reset the device.
96 //
97 NextDevStat = 0;
98 Status = VirtioFs->Virtio->SetDeviceStatus (VirtioFs->Virtio, NextDevStat);
99 if (EFI_ERROR (Status)) {
100 goto Failed;
101 }
102
103 //
104 // 2. Set the ACKNOWLEDGE status bit [...]
105 //
106 NextDevStat |= VSTAT_ACK;
107 Status = VirtioFs->Virtio->SetDeviceStatus (VirtioFs->Virtio, NextDevStat);
108 if (EFI_ERROR (Status)) {
109 goto Failed;
110 }
111
112 //
113 // 3. Set the DRIVER status bit [...]
114 //
115 NextDevStat |= VSTAT_DRIVER;
116 Status = VirtioFs->Virtio->SetDeviceStatus (VirtioFs->Virtio, NextDevStat);
117 if (EFI_ERROR (Status)) {
118 goto Failed;
119 }
120
121 //
122 // 4. Read device feature bits...
123 //
124 Status = VirtioFs->Virtio->GetDeviceFeatures (VirtioFs->Virtio, &Features);
125 if (EFI_ERROR (Status)) {
126 goto Failed;
127 }
128
129 if ((Features & VIRTIO_F_VERSION_1) == 0) {
130 Status = EFI_UNSUPPORTED;
131 goto Failed;
132 }
133
134 //
135 // No device-specific feature bits have been defined in file "virtio-fs.tex"
136 // of the virtio spec at <https://github.com/oasis-tcs/virtio-spec.git>, as
137 // of commit 87fa6b5d8155.
138 //
139 Features &= VIRTIO_F_VERSION_1 | VIRTIO_F_IOMMU_PLATFORM;
140
141 //
142 // ... and write the subset of feature bits understood by the [...] driver to
143 // the device. [...]
144 // 5. Set the FEATURES_OK status bit.
145 // 6. Re-read device status to ensure the FEATURES_OK bit is still set [...]
146 //
147 Status = Virtio10WriteFeatures (VirtioFs->Virtio, Features, &NextDevStat);
148 if (EFI_ERROR (Status)) {
149 goto Failed;
150 }
151
152 //
153 // 7. Perform device-specific setup, including discovery of virtqueues for
154 // the device, [...] reading [...] the device's virtio configuration space
155 //
156 Status = VirtioFsReadConfig (VirtioFs->Virtio, &Config);
157 if (EFI_ERROR (Status)) {
158 goto Failed;
159 }
160
161 //
162 // 7.a. Convert the filesystem label from UTF-8 to UCS-2. Only labels with
163 // printable ASCII code points (U+0020 through U+007E) are supported.
164 // NUL-terminate at either the terminator we find, or right after the
165 // original label.
166 //
167 for (Idx = 0; Idx < VIRTIO_FS_TAG_BYTES && Config.Tag[Idx] != '\0'; Idx++) {
168 if ((Config.Tag[Idx] < 0x20) || (Config.Tag[Idx] > 0x7E)) {
169 Status = EFI_UNSUPPORTED;
170 goto Failed;
171 }
172
173 VirtioFs->Label[Idx] = Config.Tag[Idx];
174 }
175
176 VirtioFs->Label[Idx] = L'\0';
177
178 //
179 // 7.b. We need one queue for sending normal priority requests.
180 //
181 if (Config.NumReqQueues < 1) {
182 Status = EFI_UNSUPPORTED;
183 goto Failed;
184 }
185
186 //
187 // 7.c. Fetch and remember the number of descriptors we can place on the
188 // queue at once. We'll need two descriptors per request, as a minimum --
189 // request header, response header.
190 //
191 Status = VirtioFs->Virtio->SetQueueSel (
192 VirtioFs->Virtio,
193 VIRTIO_FS_REQUEST_QUEUE
194 );
195 if (EFI_ERROR (Status)) {
196 goto Failed;
197 }
198
199 Status = VirtioFs->Virtio->GetQueueNumMax (
200 VirtioFs->Virtio,
201 &VirtioFs->QueueSize
202 );
203 if (EFI_ERROR (Status)) {
204 goto Failed;
205 }
206
207 if (VirtioFs->QueueSize < 2) {
208 Status = EFI_UNSUPPORTED;
209 goto Failed;
210 }
211
212 //
213 // 7.d. [...] population of virtqueues [...]
214 //
215 Status = VirtioRingInit (
216 VirtioFs->Virtio,
217 VirtioFs->QueueSize,
218 &VirtioFs->Ring
219 );
220 if (EFI_ERROR (Status)) {
221 goto Failed;
222 }
223
224 Status = VirtioRingMap (
225 VirtioFs->Virtio,
226 &VirtioFs->Ring,
227 &RingBaseShift,
228 &VirtioFs->RingMap
229 );
230 if (EFI_ERROR (Status)) {
231 goto ReleaseQueue;
232 }
233
234 Status = VirtioFs->Virtio->SetQueueAddress (
235 VirtioFs->Virtio,
236 &VirtioFs->Ring,
237 RingBaseShift
238 );
239 if (EFI_ERROR (Status)) {
240 goto UnmapQueue;
241 }
242
243 //
244 // 8. Set the DRIVER_OK status bit.
245 //
246 NextDevStat |= VSTAT_DRIVER_OK;
247 Status = VirtioFs->Virtio->SetDeviceStatus (VirtioFs->Virtio, NextDevStat);
248 if (EFI_ERROR (Status)) {
249 goto UnmapQueue;
250 }
251
252 return EFI_SUCCESS;
253
254UnmapQueue:
255 VirtioFs->Virtio->UnmapSharedBuffer (VirtioFs->Virtio, VirtioFs->RingMap);
256
257ReleaseQueue:
258 VirtioRingUninit (VirtioFs->Virtio, &VirtioFs->Ring);
259
260Failed:
261 //
262 // If any of these steps go irrecoverably wrong, the driver SHOULD set the
263 // FAILED status bit to indicate that it has given up on the device (it can
264 // reset the device later to restart if desired). [...]
265 //
266 // Virtio access failure here should not mask the original error.
267 //
268 NextDevStat |= VSTAT_FAILED;
269 VirtioFs->Virtio->SetDeviceStatus (VirtioFs->Virtio, NextDevStat);
270
271 return Status;
272}
273
283VOID
285 IN OUT VIRTIO_FS *VirtioFs
286 )
287{
288 //
289 // Resetting the Virtio device makes it release its resources and forget its
290 // configuration.
291 //
292 VirtioFs->Virtio->SetDeviceStatus (VirtioFs->Virtio, 0);
293 VirtioFs->Virtio->UnmapSharedBuffer (VirtioFs->Virtio, VirtioFs->RingMap);
294 VirtioRingUninit (VirtioFs->Virtio, &VirtioFs->Ring);
295}
296
310VOID
311EFIAPI
313 IN EFI_EVENT ExitBootEvent,
314 IN VOID *VirtioFsAsVoid
315 )
316{
317 VIRTIO_FS *VirtioFs;
318
319 VirtioFs = VirtioFsAsVoid;
320 DEBUG ((
321 DEBUG_VERBOSE,
322 "%a: VirtioFs=0x%p Label=\"%s\"\n",
323 __func__,
324 VirtioFsAsVoid,
325 VirtioFs->Label
326 ));
327 VirtioFs->Virtio->SetDeviceStatus (VirtioFs->Virtio, 0);
328}
329
399 IN VIRTIO_FS *VirtioFs,
400 IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *RequestSgList,
401 IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *ResponseSgList OPTIONAL
402 )
403{
404 VIRTIO_FS_SCATTER_GATHER_LIST *SgListParam[2];
405 UINT16 DescriptorsNeeded;
406 UINTN ListId;
407
408 if (RequestSgList == NULL) {
409 return EFI_INVALID_PARAMETER;
410 }
411
412 SgListParam[0] = RequestSgList;
413 SgListParam[1] = ResponseSgList;
414
415 DescriptorsNeeded = 0;
416 for (ListId = 0; ListId < ARRAY_SIZE (SgListParam); ListId++) {
418 UINT32 SgListTotalSize;
419 UINTN IoVecIdx;
420
421 SgList = SgListParam[ListId];
422 if (SgList == NULL) {
423 continue;
424 }
425
426 //
427 // Sanity-check SgList -- it must provide at least one IO Vector.
428 //
429 if ((SgList->IoVec == NULL) || (SgList->NumVec == 0)) {
430 return EFI_INVALID_PARAMETER;
431 }
432
433 //
434 // Make sure that, for each IO Vector in this SgList, a virtio descriptor
435 // can be added to the virtio queue, after the other descriptors added
436 // previously.
437 //
438 if ((SgList->NumVec > (UINTN)(MAX_UINT16 - DescriptorsNeeded)) ||
439 (DescriptorsNeeded + SgList->NumVec > VirtioFs->QueueSize))
440 {
441 return EFI_UNSUPPORTED;
442 }
443
444 DescriptorsNeeded += (UINT16)SgList->NumVec;
445
446 SgListTotalSize = 0;
447 for (IoVecIdx = 0; IoVecIdx < SgList->NumVec; IoVecIdx++) {
448 VIRTIO_FS_IO_VECTOR *IoVec;
449
450 IoVec = &SgList->IoVec[IoVecIdx];
451 //
452 // Sanity-check this IoVec -- it must describe a non-empty buffer.
453 //
454 if ((IoVec->Buffer == NULL) || (IoVec->Size == 0)) {
455 return EFI_INVALID_PARAMETER;
456 }
457
458 //
459 // Make sure the cumulative size of all IO Vectors in this SgList remains
460 // expressible as a UINT32.
461 //
462 if (IoVec->Size > MAX_UINT32 - SgListTotalSize) {
463 return EFI_UNSUPPORTED;
464 }
465
466 SgListTotalSize += (UINT32)IoVec->Size;
467
468 //
469 // Initialize those fields in this IO Vector that will be updated in
470 // relation to mapping / transfer.
471 //
472 IoVec->Mapped = FALSE;
473 IoVec->MappedAddress = 0;
474 IoVec->Mapping = NULL;
475 IoVec->Transferred = 0;
476 }
477
478 //
479 // Store the cumulative size of all IO Vectors that we have calculated in
480 // this SgList.
481 //
482 SgList->TotalSize = SgListTotalSize;
483 }
484
485 return EFI_SUCCESS;
486}
487
539 IN OUT VIRTIO_FS *VirtioFs,
540 IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *RequestSgList,
541 IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *ResponseSgList OPTIONAL
542 )
543{
544 VIRTIO_FS_SCATTER_GATHER_LIST *SgListParam[2];
545 VIRTIO_MAP_OPERATION SgListVirtioMapOp[ARRAY_SIZE (SgListParam)];
546 UINT16 SgListDescriptorFlag[ARRAY_SIZE (SgListParam)];
547 UINTN ListId;
549 UINTN IoVecIdx;
550 VIRTIO_FS_IO_VECTOR *IoVec;
551 EFI_STATUS Status;
552 DESC_INDICES Indices;
553 UINT32 TotalBytesWrittenByDevice;
554 UINT32 BytesPermittedForWrite;
555
556 SgListParam[0] = RequestSgList;
557 SgListVirtioMapOp[0] = VirtioOperationBusMasterRead;
558 SgListDescriptorFlag[0] = 0;
559
560 SgListParam[1] = ResponseSgList;
561 SgListVirtioMapOp[1] = VirtioOperationBusMasterWrite;
562 SgListDescriptorFlag[1] = VRING_DESC_F_WRITE;
563
564 //
565 // Map all IO Vectors.
566 //
567 for (ListId = 0; ListId < ARRAY_SIZE (SgListParam); ListId++) {
568 SgList = SgListParam[ListId];
569 if (SgList == NULL) {
570 continue;
571 }
572
573 for (IoVecIdx = 0; IoVecIdx < SgList->NumVec; IoVecIdx++) {
574 IoVec = &SgList->IoVec[IoVecIdx];
575 //
576 // Map this IO Vector.
577 //
579 VirtioFs->Virtio,
580 SgListVirtioMapOp[ListId],
581 IoVec->Buffer,
582 IoVec->Size,
583 &IoVec->MappedAddress,
584 &IoVec->Mapping
585 );
586 if (EFI_ERROR (Status)) {
587 goto Unmap;
588 }
589
590 IoVec->Mapped = TRUE;
591 }
592 }
593
594 //
595 // Compose the descriptor chain.
596 //
597 VirtioPrepare (&VirtioFs->Ring, &Indices);
598 for (ListId = 0; ListId < ARRAY_SIZE (SgListParam); ListId++) {
599 SgList = SgListParam[ListId];
600 if (SgList == NULL) {
601 continue;
602 }
603
604 for (IoVecIdx = 0; IoVecIdx < SgList->NumVec; IoVecIdx++) {
605 UINT16 NextFlag;
606
607 IoVec = &SgList->IoVec[IoVecIdx];
608 //
609 // Set VRING_DESC_F_NEXT on all except the very last descriptor.
610 //
611 NextFlag = VRING_DESC_F_NEXT;
612 if ((ListId == ARRAY_SIZE (SgListParam) - 1) &&
613 (IoVecIdx == SgList->NumVec - 1))
614 {
615 NextFlag = 0;
616 }
617
619 &VirtioFs->Ring,
620 IoVec->MappedAddress,
621 (UINT32)IoVec->Size,
622 SgListDescriptorFlag[ListId] | NextFlag,
623 &Indices
624 );
625 }
626 }
627
628 //
629 // Submit the descriptor chain.
630 //
631 Status = VirtioFlush (
632 VirtioFs->Virtio,
633 VIRTIO_FS_REQUEST_QUEUE,
634 &VirtioFs->Ring,
635 &Indices,
636 &TotalBytesWrittenByDevice
637 );
638 if (EFI_ERROR (Status)) {
639 goto Unmap;
640 }
641
642 //
643 // Sanity-check: the Virtio Filesystem device should not have written more
644 // bytes than what we offered buffers for.
645 //
646 if (ResponseSgList == NULL) {
647 BytesPermittedForWrite = 0;
648 } else {
649 BytesPermittedForWrite = ResponseSgList->TotalSize;
650 }
651
652 if (TotalBytesWrittenByDevice > BytesPermittedForWrite) {
653 Status = EFI_DEVICE_ERROR;
654 goto Unmap;
655 }
656
657 //
658 // Update the transfer sizes in the IO Vectors.
659 //
660 for (ListId = 0; ListId < ARRAY_SIZE (SgListParam); ListId++) {
661 SgList = SgListParam[ListId];
662 if (SgList == NULL) {
663 continue;
664 }
665
666 for (IoVecIdx = 0; IoVecIdx < SgList->NumVec; IoVecIdx++) {
667 IoVec = &SgList->IoVec[IoVecIdx];
668 if (SgListVirtioMapOp[ListId] == VirtioOperationBusMasterRead) {
669 //
670 // We report that the Virtio Filesystem device has read all buffers in
671 // the request.
672 //
673 IoVec->Transferred = IoVec->Size;
674 } else {
675 //
676 // Regarding the response, calculate how much of the current IO Vector
677 // has been populated by the Virtio Filesystem device. In
678 // "TotalBytesWrittenByDevice", VirtioFlush() reported the total count
679 // across all device-writeable descriptors, in the order they were
680 // chained on the ring.
681 //
682 IoVec->Transferred = MIN (
683 (UINTN)TotalBytesWrittenByDevice,
684 IoVec->Size
685 );
686 TotalBytesWrittenByDevice -= (UINT32)IoVec->Transferred;
687 }
688 }
689 }
690
691 //
692 // By now, "TotalBytesWrittenByDevice" has been exhausted.
693 //
694 ASSERT (TotalBytesWrittenByDevice == 0);
695
696 //
697 // We've succeeded; fall through.
698 //
699Unmap:
700 //
701 // Unmap all mapped IO Vectors on both the success and the error paths. The
702 // unmapping occurs in reverse order of mapping, in an attempt to avoid
703 // memory fragmentation.
704 //
705 ListId = ARRAY_SIZE (SgListParam);
706 while (ListId > 0) {
707 --ListId;
708 SgList = SgListParam[ListId];
709 if (SgList == NULL) {
710 continue;
711 }
712
713 IoVecIdx = SgList->NumVec;
714 while (IoVecIdx > 0) {
715 EFI_STATUS UnmapStatus;
716
717 --IoVecIdx;
718 IoVec = &SgList->IoVec[IoVecIdx];
719 //
720 // Unmap this IO Vector, if it has been mapped.
721 //
722 if (!IoVec->Mapped) {
723 continue;
724 }
725
726 UnmapStatus = VirtioFs->Virtio->UnmapSharedBuffer (
727 VirtioFs->Virtio,
728 IoVec->Mapping
729 );
730 //
731 // Re-set the following fields to the values they initially got from
732 // VirtioFsSgListsValidate() -- the above unmapping attempt is considered
733 // final, even if it fails.
734 //
735 IoVec->Mapped = FALSE;
736 IoVec->MappedAddress = 0;
737 IoVec->Mapping = NULL;
738
739 //
740 // If we are on the success path, but the unmapping failed, we need to
741 // transparently flip to the failure path -- the caller must learn they
742 // should not consult the response buffers.
743 //
744 // The branch below can be taken at most once.
745 //
746 if (!EFI_ERROR (Status) && EFI_ERROR (UnmapStatus)) {
747 Status = UnmapStatus;
748 }
749 }
750 }
751
752 return Status;
753}
754
791 IN OUT VIRTIO_FS *VirtioFs,
793 IN UINT32 RequestSize,
794 IN VIRTIO_FS_FUSE_OPCODE Opcode,
795 IN UINT64 NodeId
796 )
797{
798 if (RequestSize < sizeof *Request) {
799 return EFI_INVALID_PARAMETER;
800 }
801
802 if (VirtioFs->RequestId == MAX_UINT64) {
803 return EFI_OUT_OF_RESOURCES;
804 }
805
806 Request->Len = RequestSize;
807 Request->Opcode = Opcode;
808 Request->Unique = VirtioFs->RequestId++;
809 Request->NodeId = NodeId;
810 Request->Uid = 0;
811 Request->Gid = 0;
812 Request->Pid = 1;
813 Request->Padding = 0;
814
815 return EFI_SUCCESS;
816}
817
874 IN VIRTIO_FS_SCATTER_GATHER_LIST *ResponseSgList,
875 IN UINT64 RequestId,
876 OUT UINTN *TailBufferFill
877 )
878{
879 UINTN NumFixedSizeVec;
880 VIRTIO_FS_FUSE_RESPONSE *CommonResp;
881 UINT32 TotalTransferred;
882 UINTN Idx;
883
884 //
885 // Ensured by VirtioFsSgListsValidate().
886 //
887 ASSERT (ResponseSgList->NumVec > 0);
888
889 if (TailBufferFill == NULL) {
890 //
891 // All buffers are considered fixed size.
892 //
893 NumFixedSizeVec = ResponseSgList->NumVec;
894 } else {
895 //
896 // If the last buffer is variable size, then we need that buffer to be
897 // different from the first buffer, which is considered a
898 // VIRTIO_FS_FUSE_RESPONSE (fixed size) structure.
899 //
900 if (ResponseSgList->NumVec == 1) {
901 return EFI_INVALID_PARAMETER;
902 }
903
904 NumFixedSizeVec = ResponseSgList->NumVec - 1;
905 }
906
907 //
908 // The first buffer is supposed to carry a (fully populated)
909 // VIRTIO_FS_FUSE_RESPONSE structure.
910 //
911 if (ResponseSgList->IoVec[0].Size != sizeof *CommonResp) {
912 return EFI_INVALID_PARAMETER;
913 }
914
915 if (ResponseSgList->IoVec[0].Transferred != ResponseSgList->IoVec[0].Size) {
916 return EFI_PROTOCOL_ERROR;
917 }
918
919 //
920 // FUSE must report the same number of bytes, written by the Virtio
921 // Filesystem device, as the virtio transport does.
922 //
923 CommonResp = ResponseSgList->IoVec[0].Buffer;
924 TotalTransferred = 0;
925 for (Idx = 0; Idx < ResponseSgList->NumVec; Idx++) {
926 //
927 // Integer overflow and truncation are not possible, based on
928 // VirtioFsSgListsValidate() and VirtioFsSgListsSubmit().
929 //
930 TotalTransferred += (UINT32)ResponseSgList->IoVec[Idx].Transferred;
931 }
932
933 if (CommonResp->Len != TotalTransferred) {
934 return EFI_PROTOCOL_ERROR;
935 }
936
937 //
938 // Enforce that FUSE match our request ID in the response.
939 //
940 if (CommonResp->Unique != RequestId) {
941 return EFI_PROTOCOL_ERROR;
942 }
943
944 //
945 // If there is an explicit error report, skip checking the transfer
946 // counts for the rest of the fixed size buffers.
947 //
948 if (CommonResp->Error != 0) {
949 return EFI_DEVICE_ERROR;
950 }
951
952 //
953 // There was no error reported, so we require that the Virtio Filesystem
954 // device populate all fixed size buffers. We checked this for the very first
955 // buffer above; let's check the rest (if any).
956 //
957 ASSERT (NumFixedSizeVec >= 1);
958 for (Idx = 1; Idx < NumFixedSizeVec; Idx++) {
959 if (ResponseSgList->IoVec[Idx].Transferred !=
960 ResponseSgList->IoVec[Idx].Size)
961 {
962 return EFI_PROTOCOL_ERROR;
963 }
964 }
965
966 //
967 // If the last buffer is considered variable size, report its filled size.
968 //
969 if (TailBufferFill != NULL) {
970 *TailBufferFill = ResponseSgList->IoVec[NumFixedSizeVec].Transferred;
971 }
972
973 return EFI_SUCCESS;
974}
975
992 IN INT32 Errno
993 )
994{
995 switch (Errno) {
996 case -1:// EPERM Operation not permitted
997 return EFI_SECURITY_VIOLATION;
998
999 case -2: // ENOENT No such file or directory
1000 case -3: // ESRCH No such process
1001 case -6: // ENXIO No such device or address
1002 case -10: // ECHILD No child processes
1003 case -19: // ENODEV No such device
1004 case -49: // EUNATCH Protocol driver not attached
1005 case -65: // ENOPKG Package not installed
1006 case -79: // ELIBACC Can not access a needed shared library
1007 case -126: // ENOKEY Required key not available
1008 return EFI_NOT_FOUND;
1009
1010 case -4: // EINTR Interrupted system call
1011 case -11: // EAGAIN, EWOULDBLOCK Resource temporarily unavailable
1012 case -16: // EBUSY Device or resource busy
1013 case -26: // ETXTBSY Text file busy
1014 case -35: // EDEADLK, EDEADLOCK Resource deadlock avoided
1015 case -39: // ENOTEMPTY Directory not empty
1016 case -42: // ENOMSG No message of desired type
1017 case -61: // ENODATA No data available
1018 case -85: // ERESTART Interrupted system call should be restarted
1019 return EFI_NOT_READY;
1020
1021 case -5: // EIO Input/output error
1022 case -45: // EL2NSYNC Level 2 not synchronized
1023 case -46: // EL3HLT Level 3 halted
1024 case -47: // EL3RST Level 3 reset
1025 case -51: // EL2HLT Level 2 halted
1026 case -121: // EREMOTEIO Remote I/O error
1027 case -133: // EHWPOISON Memory page has hardware error
1028 return EFI_DEVICE_ERROR;
1029
1030 case -7: // E2BIG Argument list too long
1031 case -36: // ENAMETOOLONG File name too long
1032 case -90: // EMSGSIZE Message too long
1033 return EFI_BAD_BUFFER_SIZE;
1034
1035 case -8: // ENOEXEC Exec format error
1036 case -15: // ENOTBLK Block device required
1037 case -18: // EXDEV Invalid cross-device link
1038 case -20: // ENOTDIR Not a directory
1039 case -21: // EISDIR Is a directory
1040 case -25: // ENOTTY Inappropriate ioctl for device
1041 case -27: // EFBIG File too large
1042 case -29: // ESPIPE Illegal seek
1043 case -38: // ENOSYS Function not implemented
1044 case -59: // EBFONT Bad font file format
1045 case -60: // ENOSTR Device not a stream
1046 case -83: // ELIBEXEC Cannot exec a shared library directly
1047 case -88: // ENOTSOCK Socket operation on non-socket
1048 case -91: // EPROTOTYPE Protocol wrong type for socket
1049 case -92: // ENOPROTOOPT Protocol not available
1050 case -93: // EPROTONOSUPPORT Protocol not supported
1051 case -94: // ESOCKTNOSUPPORT Socket type not supported
1052 case -95: // ENOTSUP, EOPNOTSUPP Operation not supported
1053 case -96: // EPFNOSUPPORT Protocol family not supported
1054 case -97: // EAFNOSUPPORT Address family not supported by protocol
1055 case -99: // EADDRNOTAVAIL Cannot assign requested address
1056 case -118: // ENOTNAM Not a XENIX named type file
1057 case -120: // EISNAM Is a named type file
1058 case -124: // EMEDIUMTYPE Wrong medium type
1059 return EFI_UNSUPPORTED;
1060
1061 case -9: // EBADF Bad file descriptor
1062 case -14: // EFAULT Bad address
1063 case -44: // ECHRNG Channel number out of range
1064 case -48: // ELNRNG Link number out of range
1065 case -53: // EBADR Invalid request descriptor
1066 case -56: // EBADRQC Invalid request code
1067 case -57: // EBADSLT Invalid slot
1068 case -76: // ENOTUNIQ Name not unique on network
1069 case -84: // EILSEQ Invalid or incomplete multibyte or wide character
1070 return EFI_NO_MAPPING;
1071
1072 case -12: // ENOMEM Cannot allocate memory
1073 case -23: // ENFILE Too many open files in system
1074 case -24: // EMFILE Too many open files
1075 case -31: // EMLINK Too many links
1076 case -37: // ENOLCK No locks available
1077 case -40: // ELOOP Too many levels of symbolic links
1078 case -50: // ENOCSI No CSI structure available
1079 case -55: // ENOANO No anode
1080 case -63: // ENOSR Out of streams resources
1081 case -82: // ELIBMAX Attempting to link in too many shared libraries
1082 case -87: // EUSERS Too many users
1083 case -105: // ENOBUFS No buffer space available
1084 case -109: // ETOOMANYREFS Too many references: cannot splice
1085 case -119: // ENAVAIL No XENIX semaphores available
1086 case -122: // EDQUOT Disk quota exceeded
1087 return EFI_OUT_OF_RESOURCES;
1088
1089 case -13:// EACCES Permission denied
1090 return EFI_ACCESS_DENIED;
1091
1092 case -17: // EEXIST File exists
1093 case -98: // EADDRINUSE Address already in use
1094 case -106: // EISCONN Transport endpoint is already connected
1095 case -114: // EALREADY Operation already in progress
1096 case -115: // EINPROGRESS Operation now in progress
1097 return EFI_ALREADY_STARTED;
1098
1099 case -22: // EINVAL Invalid argument
1100 case -33: // EDOM Numerical argument out of domain
1101 return EFI_INVALID_PARAMETER;
1102
1103 case -28: // ENOSPC No space left on device
1104 case -54: // EXFULL Exchange full
1105 return EFI_VOLUME_FULL;
1106
1107 case -30:// EROFS Read-only file system
1108 return EFI_WRITE_PROTECTED;
1109
1110 case -32: // EPIPE Broken pipe
1111 case -43: // EIDRM Identifier removed
1112 case -67: // ENOLINK Link has been severed
1113 case -68: // EADV Advertise error
1114 case -69: // ESRMNT Srmount error
1115 case -70: // ECOMM Communication error on send
1116 case -73: // EDOTDOT RFS specific error
1117 case -78: // EREMCHG Remote address changed
1118 case -86: // ESTRPIPE Streams pipe error
1119 case -102: // ENETRESET Network dropped connection on reset
1120 case -103: // ECONNABORTED Software caused connection abort
1121 case -104: // ECONNRESET Connection reset by peer
1122 case -116: // ESTALE Stale file handle
1123 case -125: // ECANCELED Operation canceled
1124 case -128: // EKEYREVOKED Key has been revoked
1125 case -129: // EKEYREJECTED Key was rejected by service
1126 case -130: // EOWNERDEAD Owner died
1127 case -131: // ENOTRECOVERABLE State not recoverable
1128 return EFI_ABORTED;
1129
1130 case -34: // ERANGE Numerical result out of range
1131 case -75: // EOVERFLOW Value too large for defined data type
1132 return EFI_BUFFER_TOO_SMALL;
1133
1134 case -52: // EBADE Invalid exchange
1135 case -108: // ESHUTDOWN Cannot send after transport endpoint shutdown
1136 case -111: // ECONNREFUSED Connection refused
1137 return EFI_END_OF_FILE;
1138
1139 case -62: // ETIME Timer expired
1140 case -110: // ETIMEDOUT Connection timed out
1141 case -127: // EKEYEXPIRED Key has expired
1142 return EFI_TIMEOUT;
1143
1144 case -64: // ENONET Machine is not on the network
1145 case -66: // EREMOTE Object is remote
1146 case -72: // EMULTIHOP Multihop attempted
1147 case -100: // ENETDOWN Network is down
1148 case -101: // ENETUNREACH Network is unreachable
1149 case -112: // EHOSTDOWN Host is down
1150 case -113: // EHOSTUNREACH No route to host
1151 case -123: // ENOMEDIUM No medium found
1152 case -132: // ERFKILL Operation not possible due to RF-kill
1153 return EFI_NO_MEDIA;
1154
1155 case -71:// EPROTO Protocol error
1156 return EFI_PROTOCOL_ERROR;
1157
1158 case -74: // EBADMSG Bad message
1159 case -77: // EBADFD File descriptor in bad state
1160 case -80: // ELIBBAD Accessing a corrupted shared library
1161 case -81: // ELIBSCN .lib section in a.out corrupted
1162 case -117: // EUCLEAN Structure needs cleaning
1163 return EFI_VOLUME_CORRUPTED;
1164
1165 case -89: // EDESTADDRREQ Destination address required
1166 case -107: // ENOTCONN Transport endpoint is not connected
1167 return EFI_NOT_STARTED;
1168
1169 default:
1170 break;
1171 }
1172
1173 return EFI_DEVICE_ERROR;
1174}
1175
1176//
1177// Parser states for canonicalizing a POSIX pathname.
1178//
1179typedef enum {
1180 ParserInit, // just starting
1181 ParserEnd, // finished
1182 ParserSlash, // slash(es) seen
1183 ParserDot, // one dot seen since last slash
1184 ParserDotDot, // two dots seen since last slash
1185 ParserNormal, // a different sequence seen
1186} PARSER_STATE;
1187
1204STATIC
1205VOID
1207 IN CHAR8 *Buffer,
1208 IN OUT UINTN *Position
1209 )
1210{
1211 ASSERT (*Position >= 1);
1212 ASSERT (Buffer[*Position - 1] == '/');
1213 if (*Position == 1) {
1214 return;
1215 }
1216
1217 (*Position)--;
1218}
1219
1236STATIC
1237VOID
1239 OUT CHAR8 *Buffer,
1240 IN OUT UINTN *Position,
1241 IN UINTN Size,
1242 IN CHAR8 Char8
1243 )
1244{
1245 ASSERT (*Position < Size);
1246 Buffer[(*Position)++] = Char8;
1247}
1248
1263STATIC
1264VOID
1266 IN CHAR8 *Buffer,
1267 IN OUT UINTN *Position
1268 )
1269{
1270 ASSERT (*Position >= 2);
1271 ASSERT (Buffer[*Position - 1] == '.');
1272 ASSERT (Buffer[*Position - 2] == '/');
1273 (*Position)--;
1274}
1275
1306STATIC
1307VOID
1309 IN CHAR8 *Buffer,
1310 IN OUT UINTN *Position,
1311 OUT BOOLEAN *RootEscape
1312
1313 )
1314{
1315 ASSERT (*Position >= 3);
1316 ASSERT (Buffer[*Position - 1] == '.');
1317 ASSERT (Buffer[*Position - 2] == '.');
1318 ASSERT (Buffer[*Position - 3] == '/');
1319 (*Position) -= 2;
1320
1321 if (*Position == 1) {
1322 //
1323 // Root directory slash reached; don't try to climb higher.
1324 //
1325 *RootEscape = TRUE;
1326 return;
1327 }
1328
1329 //
1330 // Skip slash.
1331 //
1332 (*Position)--;
1333 //
1334 // Scan until next slash to the left.
1335 //
1336 do {
1337 ASSERT (*Position > 0);
1338 (*Position)--;
1339 } while (Buffer[*Position] != '/');
1340
1341 (*Position)++;
1342}
1343
1405 IN CHAR8 *LhsPath8,
1406 IN CHAR16 *RhsPath16,
1407 OUT CHAR8 **ResultPath8,
1408 OUT BOOLEAN *RootEscape
1409 )
1410{
1411 UINTN RhsLen;
1412 CHAR8 *RhsPath8;
1413 UINTN Idx;
1414 EFI_STATUS Status;
1415 UINTN SizeToSanitize;
1416 CHAR8 *BufferToSanitize;
1417 CHAR8 *SanitizedBuffer;
1418 PARSER_STATE State;
1419 UINTN SanitizedPosition;
1420
1421 //
1422 // Appending an empty pathname is not allowed.
1423 //
1424 RhsLen = StrLen (RhsPath16);
1425 if (RhsLen == 0) {
1426 return EFI_INVALID_PARAMETER;
1427 }
1428
1429 //
1430 // Enforce length restriction on RhsPath16.
1431 //
1432 if (RhsLen > VIRTIO_FS_MAX_PATHNAME_LENGTH) {
1433 return EFI_INVALID_PARAMETER;
1434 }
1435
1436 //
1437 // Transliterate RhsPath16 to RhsPath8 by:
1438 // - rejecting RhsPath16 if a character outside of printable ASCII is seen,
1439 // - rejecting RhsPath16 if a forward slash is seen,
1440 // - replacing backslashes with forward slashes,
1441 // - casting the characters from CHAR16 to CHAR8.
1442 //
1443 RhsPath8 = AllocatePool (RhsLen + 1);
1444 if (RhsPath8 == NULL) {
1445 return EFI_OUT_OF_RESOURCES;
1446 }
1447
1448 for (Idx = 0; RhsPath16[Idx] != L'\0'; Idx++) {
1449 if ((RhsPath16[Idx] < 0x20) || (RhsPath16[Idx] > 0x7E) ||
1450 (RhsPath16[Idx] == L'/'))
1451 {
1452 Status = EFI_UNSUPPORTED;
1453 goto FreeRhsPath8;
1454 }
1455
1456 RhsPath8[Idx] = (CHAR8)((RhsPath16[Idx] == L'\\') ? L'/' : RhsPath16[Idx]);
1457 }
1458
1459 RhsPath8[Idx++] = '\0';
1460
1461 //
1462 // Now prepare the input for the canonicalization (squashing of sequences of
1463 // forward slashes, and eliminating . (dot) and .. (dot-dot) pathname
1464 // components).
1465 //
1466 // The sanitized path can never be longer than the naive concatenation of the
1467 // left hand side and right hand side paths, so we'll use the catenated size
1468 // for allocating the sanitized output too.
1469 //
1470 if (RhsPath8[0] == '/') {
1471 //
1472 // If the right hand side path is absolute, then it is not appended to the
1473 // left hand side path -- it *replaces* the left hand side path.
1474 //
1475 SizeToSanitize = RhsLen + 1;
1476 BufferToSanitize = RhsPath8;
1477 } else {
1478 //
1479 // If the right hand side path is relative, then it is appended (naively)
1480 // to the left hand side.
1481 //
1482 UINTN LhsLen;
1483
1484 LhsLen = AsciiStrLen (LhsPath8);
1485 SizeToSanitize = LhsLen + 1 + RhsLen + 1;
1486 BufferToSanitize = AllocatePool (SizeToSanitize);
1487 if (BufferToSanitize == NULL) {
1488 Status = EFI_OUT_OF_RESOURCES;
1489 goto FreeRhsPath8;
1490 }
1491
1492 CopyMem (BufferToSanitize, LhsPath8, LhsLen);
1493 BufferToSanitize[LhsLen] = '/';
1494 CopyMem (BufferToSanitize + LhsLen + 1, RhsPath8, RhsLen + 1);
1495 }
1496
1497 //
1498 // Allocate the output buffer.
1499 //
1500 SanitizedBuffer = AllocatePool (SizeToSanitize);
1501 if (SanitizedBuffer == NULL) {
1502 Status = EFI_OUT_OF_RESOURCES;
1503 goto FreeBufferToSanitize;
1504 }
1505
1506 //
1507 // State machine for parsing the input and producing the canonical output
1508 // follows.
1509 //
1510 *RootEscape = FALSE;
1511 Idx = 0;
1512 State = ParserInit;
1513 SanitizedPosition = 0;
1514 do {
1515 CHAR8 Chr8;
1516
1517 ASSERT (Idx < SizeToSanitize);
1518 Chr8 = BufferToSanitize[Idx++];
1519
1520 switch (State) {
1521 case ParserInit: // just starting
1522 ASSERT (Chr8 == '/');
1523 ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
1524 State = ParserSlash;
1525 break;
1526
1527 case ParserSlash: // slash(es) seen
1528 switch (Chr8) {
1529 case '\0':
1530 ParserStripSlash (SanitizedBuffer, &SanitizedPosition);
1531 ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
1532 State = ParserEnd;
1533 break;
1534 case '/':
1535 //
1536 // skip & stay in same state
1537 //
1538 break;
1539 case '.':
1540 ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
1541 State = ParserDot;
1542 break;
1543 default:
1544 ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
1545 State = ParserNormal;
1546 break;
1547 }
1548
1549 break;
1550
1551 case ParserDot: // one dot seen since last slash
1552 switch (Chr8) {
1553 case '\0':
1554 ParserRewindDot (SanitizedBuffer, &SanitizedPosition);
1555 ParserStripSlash (SanitizedBuffer, &SanitizedPosition);
1556 ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
1557 State = ParserEnd;
1558 break;
1559 case '/':
1560 ParserRewindDot (SanitizedBuffer, &SanitizedPosition);
1561 State = ParserSlash;
1562 break;
1563 case '.':
1564 ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
1565 State = ParserDotDot;
1566 break;
1567 default:
1568 ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
1569 State = ParserNormal;
1570 break;
1571 }
1572
1573 break;
1574
1575 case ParserDotDot: // two dots seen since last slash
1576 switch (Chr8) {
1577 case '\0':
1578 ParserRewindDotDot (SanitizedBuffer, &SanitizedPosition, RootEscape);
1579 ParserStripSlash (SanitizedBuffer, &SanitizedPosition);
1580 ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
1581 State = ParserEnd;
1582 break;
1583 case '/':
1584 ParserRewindDotDot (SanitizedBuffer, &SanitizedPosition, RootEscape);
1585 State = ParserSlash;
1586 break;
1587 case '.':
1588 //
1589 // fall through
1590 //
1591 default:
1592 ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
1593 State = ParserNormal;
1594 break;
1595 }
1596
1597 break;
1598
1599 case ParserNormal: // a different sequence seen
1600 switch (Chr8) {
1601 case '\0':
1602 ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
1603 State = ParserEnd;
1604 break;
1605 case '/':
1606 ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
1607 State = ParserSlash;
1608 break;
1609 case '.':
1610 //
1611 // fall through
1612 //
1613 default:
1614 //
1615 // copy and stay in same state
1616 //
1617 ParserCopy (SanitizedBuffer, &SanitizedPosition, SizeToSanitize, Chr8);
1618 break;
1619 }
1620
1621 break;
1622
1623 default:
1624 ASSERT (FALSE);
1625 break;
1626 }
1627 } while (State != ParserEnd);
1628
1629 //
1630 // Ensure length invariant on ResultPath8.
1631 //
1632 ASSERT (SanitizedPosition >= 2);
1633 if (SanitizedPosition - 1 > VIRTIO_FS_MAX_PATHNAME_LENGTH) {
1634 Status = EFI_OUT_OF_RESOURCES;
1635 goto FreeSanitizedBuffer;
1636 }
1637
1638 *ResultPath8 = SanitizedBuffer;
1639 SanitizedBuffer = NULL;
1640 Status = EFI_SUCCESS;
1641 //
1642 // Fall through.
1643 //
1644FreeSanitizedBuffer:
1645 if (SanitizedBuffer != NULL) {
1646 FreePool (SanitizedBuffer);
1647 }
1648
1649FreeBufferToSanitize:
1650 if (RhsPath8[0] != '/') {
1651 FreePool (BufferToSanitize);
1652 }
1653
1654FreeRhsPath8:
1655 FreePool (RhsPath8);
1656 return Status;
1657}
1658
1702 IN OUT VIRTIO_FS *VirtioFs,
1703 IN OUT CHAR8 *Path,
1704 OUT UINT64 *DirNodeId,
1705 OUT CHAR8 **LastComponent
1706 )
1707{
1708 UINT64 ParentDirNodeId;
1709 CHAR8 *Slash;
1710 EFI_STATUS Status;
1711 UINT64 NextDirNodeId;
1712
1713 if (AsciiStrCmp (Path, "/") == 0) {
1714 return EFI_INVALID_PARAMETER;
1715 }
1716
1717 ParentDirNodeId = VIRTIO_FS_FUSE_ROOT_DIR_NODE_ID;
1718 Slash = Path;
1719 for ( ; ;) {
1720 CHAR8 *NextSlash;
1723
1724 //
1725 // Find the slash (if any) that terminates the next pathname component.
1726 //
1727 NextSlash = AsciiStrStr (Slash + 1, "/");
1728 if (NextSlash == NULL) {
1729 break;
1730 }
1731
1732 //
1733 // Temporarily replace the found slash character with a NUL in-place, for
1734 // easy construction of the single-component filename that we need to look
1735 // up.
1736 //
1737 *NextSlash = '\0';
1738 Status = VirtioFsFuseLookup (
1739 VirtioFs,
1740 ParentDirNodeId,
1741 Slash + 1,
1742 &NextDirNodeId,
1743 &FuseAttr
1744 );
1745 *NextSlash = '/';
1746
1747 //
1748 // We're done with the directory inode that was the basis for the lookup.
1749 //
1750 if (ParentDirNodeId != VIRTIO_FS_FUSE_ROOT_DIR_NODE_ID) {
1751 VirtioFsFuseForget (VirtioFs, ParentDirNodeId);
1752 }
1753
1754 //
1755 // If we couldn't look up the next *non-final* pathname component, bail.
1756 //
1757 if (EFI_ERROR (Status)) {
1758 return Status;
1759 }
1760
1761 //
1762 // Lookup successful; now check if the next (non-final) component is a
1763 // directory. If not, bail.
1764 //
1765 Status = VirtioFsFuseAttrToEfiFileInfo (&FuseAttr, &FileInfo);
1766 if (EFI_ERROR (Status)) {
1767 goto ForgetNextDirNodeId;
1768 }
1769
1770 if ((FileInfo.Attribute & EFI_FILE_DIRECTORY) == 0) {
1771 Status = EFI_ACCESS_DENIED;
1772 goto ForgetNextDirNodeId;
1773 }
1774
1775 //
1776 // Advance.
1777 //
1778 ParentDirNodeId = NextDirNodeId;
1779 Slash = NextSlash;
1780 }
1781
1782 //
1783 // ParentDirNodeId corresponds to the last containing directory. The
1784 // remaining single-component filename represents a direct child under that
1785 // directory. Said filename starts at (Slash + 1).
1786 //
1787 *DirNodeId = ParentDirNodeId;
1788 *LastComponent = Slash + 1;
1789 return EFI_SUCCESS;
1790
1791ForgetNextDirNodeId:
1792 VirtioFsFuseForget (VirtioFs, NextDirNodeId);
1793 return Status;
1794}
1795
1824 IN CHAR8 *Path,
1825 OUT CHAR16 *Basename OPTIONAL,
1826 IN OUT UINTN *BasenameSize
1827 )
1828{
1829 UINTN AllocSize;
1830 UINTN LastComponent;
1831 UINTN Idx;
1832 UINTN PathSize;
1833
1834 AllocSize = *BasenameSize;
1835
1836 LastComponent = MAX_UINTN;
1837 for (Idx = 0; Path[Idx] != '\0'; Idx++) {
1838 if (Path[Idx] == '/') {
1839 LastComponent = Idx;
1840 }
1841 }
1842
1843 PathSize = Idx + 1;
1844 ASSERT (LastComponent < MAX_UINTN);
1845 LastComponent++;
1846 *BasenameSize = (PathSize - LastComponent) * sizeof Basename[0];
1847
1848 if (*BasenameSize > AllocSize) {
1849 return EFI_BUFFER_TOO_SMALL;
1850 }
1851
1852 for (Idx = LastComponent; Idx < PathSize; Idx++) {
1853 Basename[Idx - LastComponent] = Path[Idx];
1854 }
1855
1856 return EFI_SUCCESS;
1857}
1858
1919 IN CHAR8 *LhsPath8,
1920 IN CHAR16 *RhsPath16,
1921 OUT CHAR8 **ResultPath8,
1922 OUT BOOLEAN *RootEscape
1923 )
1924{
1925 //
1926 // Lengths are expressed as numbers of characters (CHAR8 or CHAR16),
1927 // excluding terminating NULs. Sizes are expressed as byte counts, including
1928 // the bytes taken up by terminating NULs.
1929 //
1930 UINTN RhsLen;
1931 UINTN LhsBasename16Size;
1932 EFI_STATUS Status;
1933 UINTN LhsBasenameLen;
1934 UINTN DestSuffix16Size;
1935 CHAR16 *DestSuffix16;
1936 CHAR8 *DestPrefix8;
1937
1938 //
1939 // An empty destination operand for the rename/move operation is not allowed.
1940 //
1941 RhsLen = StrLen (RhsPath16);
1942 if (RhsLen == 0) {
1943 return EFI_INVALID_PARAMETER;
1944 }
1945
1946 //
1947 // Enforce length restriction on RhsPath16.
1948 //
1949 if (RhsLen > VIRTIO_FS_MAX_PATHNAME_LENGTH) {
1950 return EFI_INVALID_PARAMETER;
1951 }
1952
1953 //
1954 // Determine the length of the basename of LhsPath8.
1955 //
1956 LhsBasename16Size = 0;
1957 Status = VirtioFsGetBasename (LhsPath8, NULL, &LhsBasename16Size);
1958 ASSERT (Status == EFI_BUFFER_TOO_SMALL);
1959 ASSERT (LhsBasename16Size >= sizeof (CHAR16));
1960 ASSERT (LhsBasename16Size % sizeof (CHAR16) == 0);
1961 LhsBasenameLen = LhsBasename16Size / sizeof (CHAR16) - 1;
1962 if (LhsBasenameLen == 0) {
1963 //
1964 // The root directory cannot be renamed/moved.
1965 //
1966 return EFI_INVALID_PARAMETER;
1967 }
1968
1969 //
1970 // Resolve the "move into directory" convenience form in RhsPath16.
1971 //
1972 if (RhsPath16[RhsLen - 1] == L'\\') {
1973 //
1974 // Append the basename of LhsPath8 as a CHAR16 string to RhsPath16.
1975 //
1976 DestSuffix16Size = RhsLen * sizeof (CHAR16) + LhsBasename16Size;
1977 DestSuffix16 = AllocatePool (DestSuffix16Size);
1978 if (DestSuffix16 == NULL) {
1979 return EFI_OUT_OF_RESOURCES;
1980 }
1981
1982 CopyMem (DestSuffix16, RhsPath16, RhsLen * sizeof (CHAR16));
1983 Status = VirtioFsGetBasename (
1984 LhsPath8,
1985 DestSuffix16 + RhsLen,
1986 &LhsBasename16Size
1987 );
1988 ASSERT_EFI_ERROR (Status);
1989 } else {
1990 //
1991 // Just create a copy of RhsPath16.
1992 //
1993 DestSuffix16Size = (RhsLen + 1) * sizeof (CHAR16);
1994 DestSuffix16 = AllocateCopyPool (DestSuffix16Size, RhsPath16);
1995 if (DestSuffix16 == NULL) {
1996 return EFI_OUT_OF_RESOURCES;
1997 }
1998 }
1999
2000 //
2001 // If the destination operand is absolute, it will be interpreted relative to
2002 // the root directory.
2003 //
2004 // Otherwise (i.e., if the destination operand is relative), then create the
2005 // canonical pathname that the destination operand is interpreted relatively
2006 // to; that is, the canonical pathname of the most specific parent directory
2007 // found in LhsPath8.
2008 //
2009 if (DestSuffix16[0] == L'\\') {
2010 DestPrefix8 = AllocateCopyPool (sizeof "/", "/");
2011 if (DestPrefix8 == NULL) {
2012 Status = EFI_OUT_OF_RESOURCES;
2013 goto FreeDestSuffix16;
2014 }
2015 } else {
2016 UINTN LhsLen;
2017 UINTN DestPrefixLen;
2018
2019 //
2020 // Strip the basename of LhsPath8.
2021 //
2022 LhsLen = AsciiStrLen (LhsPath8);
2023 ASSERT (LhsBasenameLen < LhsLen);
2024 DestPrefixLen = LhsLen - LhsBasenameLen;
2025 ASSERT (LhsPath8[DestPrefixLen - 1] == '/');
2026 //
2027 // If we're not at the root directory, strip the slash too.
2028 //
2029 if (DestPrefixLen > 1) {
2030 DestPrefixLen--;
2031 }
2032
2033 DestPrefix8 = AllocatePool (DestPrefixLen + 1);
2034 if (DestPrefix8 == NULL) {
2035 Status = EFI_OUT_OF_RESOURCES;
2036 goto FreeDestSuffix16;
2037 }
2038
2039 CopyMem (DestPrefix8, LhsPath8, DestPrefixLen);
2040 DestPrefix8[DestPrefixLen] = '\0';
2041 }
2042
2043 //
2044 // Now combine DestPrefix8 and DestSuffix16 into the final canonical
2045 // pathname.
2046 //
2047 Status = VirtioFsAppendPath (
2048 DestPrefix8,
2049 DestSuffix16,
2050 ResultPath8,
2051 RootEscape
2052 );
2053
2054 FreePool (DestPrefix8);
2055 //
2056 // Fall through.
2057 //
2058FreeDestSuffix16:
2059 FreePool (DestSuffix16);
2060
2061 return Status;
2062}
2063
2093 )
2094{
2095 UINT64 EpochTime[3];
2096 EFI_TIME *ConvertedTime[ARRAY_SIZE (EpochTime)];
2097 UINTN Idx;
2098
2099 FileInfo->FileSize = FuseAttr->Size;
2100
2101 //
2102 // The unit for FuseAttr->Blocks is 512B.
2103 //
2104 if (FuseAttr->Blocks >= BIT55) {
2105 return EFI_UNSUPPORTED;
2106 }
2107
2108 FileInfo->PhysicalSize = LShiftU64 (FuseAttr->Blocks, 9);
2109
2110 //
2111 // Convert the timestamps. File creation time is not tracked by the Virtio
2112 // Filesystem device, so set FileInfo->CreateTime from FuseAttr->Mtime as
2113 // well.
2114 //
2115 EpochTime[0] = FuseAttr->Mtime;
2116 EpochTime[1] = FuseAttr->Atime;
2117 EpochTime[2] = FuseAttr->Mtime;
2118 ConvertedTime[0] = &FileInfo->CreateTime;
2119 ConvertedTime[1] = &FileInfo->LastAccessTime;
2120 ConvertedTime[2] = &FileInfo->ModificationTime;
2121
2122 for (Idx = 0; Idx < ARRAY_SIZE (EpochTime); Idx++) {
2123 //
2124 // EpochToEfiTime() takes a UINTN for seconds.
2125 //
2126 if (EpochTime[Idx] > MAX_UINTN) {
2127 return EFI_UNSUPPORTED;
2128 }
2129
2130 //
2131 // Set the following fields in the converted time: Year, Month, Day, Hour,
2132 // Minute, Second, Nanosecond.
2133 //
2134 EpochToEfiTime ((UINTN)EpochTime[Idx], ConvertedTime[Idx]);
2135 //
2136 // The times are all expressed in UTC. Consequently, they are not affected
2137 // by daylight saving.
2138 //
2139 ConvertedTime[Idx]->TimeZone = 0;
2140 ConvertedTime[Idx]->Daylight = 0;
2141 //
2142 // Clear the padding fields.
2143 //
2144 ConvertedTime[Idx]->Pad1 = 0;
2145 ConvertedTime[Idx]->Pad2 = 0;
2146 }
2147
2148 //
2149 // Set the attributes.
2150 //
2151 switch (FuseAttr->Mode & VIRTIO_FS_FUSE_MODE_TYPE_MASK) {
2152 case VIRTIO_FS_FUSE_MODE_TYPE_DIR:
2153 FileInfo->Attribute = EFI_FILE_DIRECTORY;
2154 break;
2155 case VIRTIO_FS_FUSE_MODE_TYPE_REG:
2156 FileInfo->Attribute = 0;
2157 break;
2158 default:
2159 //
2160 // Other file types are not supported.
2161 //
2162 return EFI_UNSUPPORTED;
2163 }
2164
2165 //
2166 // Report the regular file or directory as read-only if all classes lack
2167 // write permission.
2168 //
2169 if ((FuseAttr->Mode & (VIRTIO_FS_FUSE_MODE_PERM_WUSR |
2170 VIRTIO_FS_FUSE_MODE_PERM_WGRP |
2171 VIRTIO_FS_FUSE_MODE_PERM_WOTH)) == 0)
2172 {
2173 FileInfo->Attribute |= EFI_FILE_READ_ONLY;
2174 }
2175
2176 //
2177 // A hard link count greater than 1 is not supported for regular files.
2178 //
2179 if (((FileInfo->Attribute & EFI_FILE_DIRECTORY) == 0) && (FuseAttr->Nlink > 1)) {
2180 return EFI_UNSUPPORTED;
2181 }
2182
2183 return EFI_SUCCESS;
2184}
2185
2222 )
2223{
2224 UINTN DirentSize;
2225 UINTN FileInfoSize;
2226 UINT8 *DirentName;
2227 UINT32 Idx;
2228
2229 DirentSize = VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE_SIZE (FuseDirent->Namelen);
2230 if (DirentSize == 0) {
2231 return EFI_INVALID_PARAMETER;
2232 }
2233
2234 //
2235 // We're now safe from overflow in the calculation below.
2236 //
2237 FileInfoSize = (OFFSET_OF (EFI_FILE_INFO, FileName) +
2238 ((UINTN)FuseDirent->Namelen + 1) * sizeof (CHAR16));
2239 if (FileInfoSize > FileInfo->Size) {
2240 return EFI_BUFFER_TOO_SMALL;
2241 }
2242
2243 //
2244 // Convert the name.
2245 //
2246 DirentName = (UINT8 *)(FuseDirent + 1);
2247 for (Idx = 0; Idx < FuseDirent->Namelen; Idx++) {
2248 UINT8 NameByte;
2249
2250 NameByte = DirentName[Idx];
2251 if ((NameByte < 0x20) || (NameByte > 0x7E) ||
2252 (NameByte == '/') || (NameByte == '\\'))
2253 {
2254 return EFI_UNSUPPORTED;
2255 }
2256
2257 FileInfo->FileName[Idx] = (CHAR16)NameByte;
2258 }
2259
2260 FileInfo->FileName[Idx++] = L'\0';
2261 //
2262 // Set the (possibly reduced) size.
2263 //
2264 FileInfo->Size = FileInfoSize;
2265
2266 return EFI_SUCCESS;
2267}
2268
2289VOID
2291 IN EFI_FILE_INFO *Info,
2292 IN EFI_FILE_INFO *NewInfo,
2293 OUT BOOLEAN *Update,
2294 OUT UINT64 *Size
2295 )
2296{
2297 BOOLEAN IsDirectory;
2298
2299 IsDirectory = (BOOLEAN)((Info->Attribute & EFI_FILE_DIRECTORY) != 0);
2300
2301 if (IsDirectory || (Info->FileSize == NewInfo->FileSize)) {
2302 *Update = FALSE;
2303 return;
2304 }
2305
2306 *Update = TRUE;
2307 *Size = NewInfo->FileSize;
2308}
2309
2356 IN EFI_FILE_INFO *Info,
2357 IN EFI_FILE_INFO *NewInfo,
2358 OUT BOOLEAN *UpdateAtime,
2359 OUT BOOLEAN *UpdateMtime,
2360 OUT UINT64 *Atime,
2361 OUT UINT64 *Mtime
2362 )
2363{
2364 EFI_TIME *Time[3];
2365 EFI_TIME *NewTime[ARRAY_SIZE (Time)];
2366 UINTN Idx;
2367 STATIC CONST EFI_TIME ZeroTime = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
2368 BOOLEAN Change[ARRAY_SIZE (Time)];
2369 UINT64 Seconds[ARRAY_SIZE (Time)];
2370
2371 Time[0] = &Info->CreateTime;
2372 Time[1] = &Info->LastAccessTime;
2373 Time[2] = &Info->ModificationTime;
2374 NewTime[0] = &NewInfo->CreateTime;
2375 NewTime[1] = &NewInfo->LastAccessTime;
2376 NewTime[2] = &NewInfo->ModificationTime;
2377
2378 //
2379 // Determine which timestamps differ from the current state. (A zero time
2380 // means "don't update", per UEFI spec.) For each timestamp that's being
2381 // changed, calculate the seconds since the Epoch.
2382 //
2383 for (Idx = 0; Idx < ARRAY_SIZE (Time); Idx++) {
2384 if ((CompareMem (NewTime[Idx], &ZeroTime, sizeof (EFI_TIME)) == 0) ||
2385 (CompareMem (NewTime[Idx], Time[Idx], sizeof (EFI_TIME)) == 0))
2386 {
2387 Change[Idx] = FALSE;
2388 } else {
2389 if (!IsTimeValid (NewTime[Idx])) {
2390 return EFI_INVALID_PARAMETER;
2391 }
2392
2393 Change[Idx] = TRUE;
2394 Seconds[Idx] = EfiTimeToEpoch (NewTime[Idx]);
2395 }
2396 }
2397
2398 //
2399 // If a change is requested for exactly one of CreateTime and
2400 // ModificationTime, we'll change the last modification time. If changes are
2401 // requested for both, and to the same timestamp, we'll similarly update the
2402 // last modification time. If changes are requested for both, but to
2403 // different timestamps, we reject the request.
2404 //
2405 if (Change[0] && Change[2] && (Seconds[0] != Seconds[2])) {
2406 return EFI_ACCESS_DENIED;
2407 }
2408
2409 *UpdateAtime = FALSE;
2410 *UpdateMtime = FALSE;
2411
2412 if (Change[0]) {
2413 *UpdateMtime = TRUE;
2414 *Mtime = Seconds[0];
2415 }
2416
2417 if (Change[1]) {
2418 *UpdateAtime = TRUE;
2419 *Atime = Seconds[1];
2420 }
2421
2422 if (Change[2]) {
2423 *UpdateMtime = TRUE;
2424 *Mtime = Seconds[2];
2425 }
2426
2427 return EFI_SUCCESS;
2428}
2429
2460 IN EFI_FILE_INFO *Info,
2461 IN EFI_FILE_INFO *NewInfo,
2462 OUT BOOLEAN *Update,
2463 OUT UINT32 *Mode
2464 )
2465{
2466 UINT64 Toggle;
2467 BOOLEAN IsDirectory;
2468 BOOLEAN IsWriteable;
2469 BOOLEAN WillBeWriteable;
2470
2471 Toggle = Info->Attribute ^ NewInfo->Attribute;
2472 if ((Toggle & ~EFI_FILE_VALID_ATTR) != 0) {
2473 //
2474 // Unknown attribute requested.
2475 //
2476 return EFI_ACCESS_DENIED;
2477 }
2478
2479 if ((Toggle & EFI_FILE_DIRECTORY) != 0) {
2480 //
2481 // EFI_FILE_DIRECTORY cannot be toggled.
2482 //
2483 return EFI_ACCESS_DENIED;
2484 }
2485
2486 IsDirectory = (BOOLEAN)((Info->Attribute & EFI_FILE_DIRECTORY) != 0);
2487 IsWriteable = (BOOLEAN)((Info->Attribute & EFI_FILE_READ_ONLY) == 0);
2488 WillBeWriteable = (BOOLEAN)((NewInfo->Attribute & EFI_FILE_READ_ONLY) == 0);
2489
2490 if (IsWriteable == WillBeWriteable) {
2491 *Update = FALSE;
2492 return EFI_SUCCESS;
2493 }
2494
2495 if (IsDirectory) {
2496 if (WillBeWriteable) {
2497 *Mode = (VIRTIO_FS_FUSE_MODE_PERM_RWXU |
2498 VIRTIO_FS_FUSE_MODE_PERM_RWXG |
2499 VIRTIO_FS_FUSE_MODE_PERM_RWXO);
2500 } else {
2501 *Mode = (VIRTIO_FS_FUSE_MODE_PERM_RUSR |
2502 VIRTIO_FS_FUSE_MODE_PERM_XUSR |
2503 VIRTIO_FS_FUSE_MODE_PERM_RGRP |
2504 VIRTIO_FS_FUSE_MODE_PERM_XGRP |
2505 VIRTIO_FS_FUSE_MODE_PERM_ROTH |
2506 VIRTIO_FS_FUSE_MODE_PERM_XOTH);
2507 }
2508 } else {
2509 if (WillBeWriteable) {
2510 *Mode = (VIRTIO_FS_FUSE_MODE_PERM_RUSR |
2511 VIRTIO_FS_FUSE_MODE_PERM_WUSR |
2512 VIRTIO_FS_FUSE_MODE_PERM_RGRP |
2513 VIRTIO_FS_FUSE_MODE_PERM_WGRP |
2514 VIRTIO_FS_FUSE_MODE_PERM_ROTH |
2515 VIRTIO_FS_FUSE_MODE_PERM_WOTH);
2516 } else {
2517 *Mode = (VIRTIO_FS_FUSE_MODE_PERM_RUSR |
2518 VIRTIO_FS_FUSE_MODE_PERM_RGRP |
2519 VIRTIO_FS_FUSE_MODE_PERM_ROTH);
2520 }
2521 }
2522
2523 *Update = TRUE;
2524 return EFI_SUCCESS;
2525}
UINT64 UINTN
UINTN EFIAPI AsciiStrLen(IN CONST CHAR8 *String)
Definition: String.c:641
INTN EFIAPI AsciiStrCmp(IN CONST CHAR8 *FirstString, IN CONST CHAR8 *SecondString)
Definition: String.c:716
UINT64 EFIAPI LShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: LShiftU64.c:28
UINTN EFIAPI StrLen(IN CONST CHAR16 *String)
Definition: String.c:30
CHAR8 *EFIAPI AsciiStrStr(IN CONST CHAR8 *String, IN CONST CHAR8 *SearchString)
Definition: String.c:931
INTN EFIAPI CompareMem(IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID EFIAPI FreePool(IN VOID *Buffer)
VOID *EFIAPI AllocateCopyPool(IN UINTN AllocationSize, IN CONST VOID *Buffer)
EFI_STATUS VirtioFsFuseForget(IN OUT VIRTIO_FS *VirtioFs, IN UINT64 NodeId)
Definition: FuseForget.c:36
EFI_STATUS VirtioFsFuseLookup(IN OUT VIRTIO_FS *VirtioFs, IN UINT64 DirNodeId, IN CHAR8 *Name, OUT UINT64 *NodeId, OUT VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE *FuseAttr)
Definition: FuseLookup.c:54
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define STATIC
Definition: Base.h:264
#define MIN(a, b)
Definition: Base.h:1007
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define ARRAY_SIZE(Array)
Definition: Base.h:1393
#define IN
Definition: Base.h:279
#define OFFSET_OF(TYPE, Field)
Definition: Base.h:758
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
EFI_FILE_INFO * FileInfo(IN EFI_FILE_HANDLE FHand)
UINTN EFIAPI EfiTimeToEpoch(IN EFI_TIME *Time)
Definition: TimeBaseLib.c:119
VOID EFIAPI EpochToEfiTime(IN UINTN EpochSeconds, OUT EFI_TIME *Time)
Definition: TimeBaseLib.c:25
BOOLEAN EFIAPI IsTimeValid(IN EFI_TIME *Time)
Definition: TimeBaseLib.c:269
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
#define VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE_SIZE(Namelen)
Definition: VirtioFs.h:147
STATIC VOID ParserRewindDot(IN CHAR8 *Buffer, IN OUT UINTN *Position)
Definition: Helpers.c:1265
EFI_STATUS VirtioFsFuseDirentPlusToEfiFileInfo(IN VIRTIO_FS_FUSE_DIRENTPLUS_RESPONSE *FuseDirent, IN OUT EFI_FILE_INFO *FileInfo)
Definition: Helpers.c:2219
EFI_STATUS VirtioFsGetFuseModeUpdate(IN EFI_FILE_INFO *Info, IN EFI_FILE_INFO *NewInfo, OUT BOOLEAN *Update, OUT UINT32 *Mode)
Definition: Helpers.c:2459
VOID EFIAPI VirtioFsExitBoot(IN EFI_EVENT ExitBootEvent, IN VOID *VirtioFsAsVoid)
Definition: Helpers.c:312
STATIC VOID ParserStripSlash(IN CHAR8 *Buffer, IN OUT UINTN *Position)
Definition: Helpers.c:1206
STATIC VOID ParserCopy(OUT CHAR8 *Buffer, IN OUT UINTN *Position, IN UINTN Size, IN CHAR8 Char8)
Definition: Helpers.c:1238
VOID VirtioFsGetFuseSizeUpdate(IN EFI_FILE_INFO *Info, IN EFI_FILE_INFO *NewInfo, OUT BOOLEAN *Update, OUT UINT64 *Size)
Definition: Helpers.c:2290
EFI_STATUS VirtioFsGetBasename(IN CHAR8 *Path, OUT CHAR16 *Basename OPTIONAL, IN OUT UINTN *BasenameSize)
Definition: Helpers.c:1823
EFI_STATUS VirtioFsFuseCheckResponse(IN VIRTIO_FS_SCATTER_GATHER_LIST *ResponseSgList, IN UINT64 RequestId, OUT UINTN *TailBufferFill)
Definition: Helpers.c:873
VOID VirtioFsUninit(IN OUT VIRTIO_FS *VirtioFs)
Definition: Helpers.c:284
EFI_STATUS VirtioFsLookupMostSpecificParentDir(IN OUT VIRTIO_FS *VirtioFs, IN OUT CHAR8 *Path, OUT UINT64 *DirNodeId, OUT CHAR8 **LastComponent)
Definition: Helpers.c:1701
EFI_STATUS VirtioFsFuseNewRequest(IN OUT VIRTIO_FS *VirtioFs, OUT VIRTIO_FS_FUSE_REQUEST *Request, IN UINT32 RequestSize, IN VIRTIO_FS_FUSE_OPCODE Opcode, IN UINT64 NodeId)
Definition: Helpers.c:790
EFI_STATUS VirtioFsInit(IN OUT VIRTIO_FS *VirtioFs)
Definition: Helpers.c:80
EFI_STATUS VirtioFsAppendPath(IN CHAR8 *LhsPath8, IN CHAR16 *RhsPath16, OUT CHAR8 **ResultPath8, OUT BOOLEAN *RootEscape)
Definition: Helpers.c:1404
EFI_STATUS VirtioFsSgListsSubmit(IN OUT VIRTIO_FS *VirtioFs, IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *RequestSgList, IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *ResponseSgList OPTIONAL)
Definition: Helpers.c:538
STATIC EFI_STATUS VirtioFsReadConfig(IN VIRTIO_DEVICE_PROTOCOL *Virtio, OUT VIRTIO_FS_CONFIG *Config)
Definition: Helpers.c:31
EFI_STATUS VirtioFsGetFuseTimeUpdates(IN EFI_FILE_INFO *Info, IN EFI_FILE_INFO *NewInfo, OUT BOOLEAN *UpdateAtime, OUT BOOLEAN *UpdateMtime, OUT UINT64 *Atime, OUT UINT64 *Mtime)
Definition: Helpers.c:2355
EFI_STATUS VirtioFsFuseAttrToEfiFileInfo(IN VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE *FuseAttr, OUT EFI_FILE_INFO *FileInfo)
Definition: Helpers.c:2090
EFI_STATUS VirtioFsErrnoToEfiStatus(IN INT32 Errno)
Definition: Helpers.c:991
EFI_STATUS VirtioFsSgListsValidate(IN VIRTIO_FS *VirtioFs, IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *RequestSgList, IN OUT VIRTIO_FS_SCATTER_GATHER_LIST *ResponseSgList OPTIONAL)
Definition: Helpers.c:398
EFI_STATUS VirtioFsComposeRenameDestination(IN CHAR8 *LhsPath8, IN CHAR16 *RhsPath16, OUT CHAR8 **ResultPath8, OUT BOOLEAN *RootEscape)
Definition: Helpers.c:1918
STATIC VOID ParserRewindDotDot(IN CHAR8 *Buffer, IN OUT UINTN *Position, OUT BOOLEAN *RootEscape)
Definition: Helpers.c:1308
EFI_STATUS EFIAPI VirtioMapAllBytesInSharedBuffer(IN VIRTIO_DEVICE_PROTOCOL *VirtIo, IN VIRTIO_MAP_OPERATION Operation, IN VOID *HostAddress, IN UINTN NumberOfBytes, OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, OUT VOID **Mapping)
Definition: VirtioLib.c:469
VOID EFIAPI VirtioAppendDesc(IN OUT VRING *Ring, IN UINT64 BufferDeviceAddress, IN UINT32 BufferSize, IN UINT16 Flags, IN OUT DESC_INDICES *Indices)
Definition: VirtioLib.c:228
EFI_STATUS EFIAPI VirtioFlush(IN VIRTIO_DEVICE_PROTOCOL *VirtIo, IN UINT16 VirtQueueId, IN OUT VRING *Ring, IN DESC_INDICES *Indices, OUT UINT32 *UsedLen OPTIONAL)
Definition: VirtioLib.c:274
EFI_STATUS EFIAPI VirtioRingMap(IN VIRTIO_DEVICE_PROTOCOL *VirtIo, IN VRING *Ring, OUT UINT64 *RingBaseShift, OUT VOID **Mapping)
Definition: VirtioLib.c:529
EFI_STATUS EFIAPI Virtio10WriteFeatures(IN VIRTIO_DEVICE_PROTOCOL *VirtIo, IN UINT64 Features, IN OUT UINT8 *DeviceStatus)
Definition: VirtioLib.c:391
VOID EFIAPI VirtioPrepare(IN OUT VRING *Ring, OUT DESC_INDICES *Indices)
Definition: VirtioLib.c:167
EFI_STATUS EFIAPI VirtioRingInit(IN VIRTIO_DEVICE_PROTOCOL *VirtIo, IN UINT16 QueueSize, OUT VRING *Ring)
Definition: VirtioLib.c:49
VOID EFIAPI VirtioRingUninit(IN VIRTIO_DEVICE_PROTOCOL *VirtIo, IN OUT VRING *Ring)
Definition: VirtioLib.c:144
EFI_TIME ModificationTime
Definition: FileInfo.h:43
UINT64 PhysicalSize
Definition: FileInfo.h:31
EFI_TIME CreateTime
Definition: FileInfo.h:35
UINT64 Size
Definition: FileInfo.h:23
UINT64 Attribute
Definition: FileInfo.h:47
CHAR16 FileName[1]
Definition: FileInfo.h:52
EFI_TIME LastAccessTime
Definition: FileInfo.h:39
UINT64 FileSize
Definition: FileInfo.h:27