]> git.proxmox.com Git - mirror_edk2.git/blob - UnixPkg/UnixBlockIoDxe/UnixBlockIo.c
Integrate patch from Andrew Fish to make it run on OS X.
[mirror_edk2.git] / UnixPkg / UnixBlockIoDxe / UnixBlockIo.c
1 /*++
2
3 Copyright (c) 2004 - 2009, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 UnixBlockIo.c
15
16 Abstract:
17
18 Produce block IO abstractions for real devices on your PC using Posix APIs.
19 The configuration of what devices to mount or emulate comes from UNIX
20 environment variables. The variables must be visible to the Microsoft*
21 Developer Studio for them to work.
22
23 <F>ixed - Fixed disk like a hard drive.
24 <R>emovable - Removable media like a floppy or CD-ROM.
25 Read <O>nly - Write protected device.
26 Read <W>rite - Read write device.
27 <block count> - Decimal number of blocks a device supports.
28 <block size> - Decimal number of bytes per block.
29
30 UNIX envirnonment variable contents. '<' and '>' are not part of the variable,
31 they are just used to make this help more readable. There should be no
32 spaces between the ';'. Extra spaces will break the variable. A '!' is
33 used to seperate multiple devices in a variable.
34
35 EFI_UNIX_VIRTUAL_DISKS =
36 <F | R><O | W>;<block count>;<block size>[!...]
37
38 EFI_UNIX_PHYSICAL_DISKS =
39 <drive letter>:<F | R><O | W>;<block count>;<block size>[!...]
40
41 Virtual Disks: These devices use a file to emulate a hard disk or removable
42 media device.
43
44 Thus a 20 MB emulated hard drive would look like:
45 EFI_UNIX_VIRTUAL_DISKS=FW;40960;512
46
47 A 1.44MB emulated floppy with a block size of 1024 would look like:
48 EFI_UNIX_VIRTUAL_DISKS=RW;1440;1024
49
50 Physical Disks: These devices use UNIX to open a real device in your system
51
52 Thus a 120 MB floppy would look like:
53 EFI_UNIX_PHYSICAL_DISKS=B:RW;245760;512
54
55 Thus a standard CD-ROM floppy would look like:
56 EFI_UNIX_PHYSICAL_DISKS=Z:RO;307200;2048
57
58
59 * Other names and brands may be claimed as the property of others.
60
61 --*/
62
63 #include <fcntl.h>
64 #include <unistd.h>
65 #include "UnixBlockIo.h"
66
67 //
68 // Block IO protocol member functions
69 //
70 EFI_STATUS
71 EFIAPI
72 UnixBlockIoReadBlocks (
73 IN EFI_BLOCK_IO_PROTOCOL *This,
74 IN UINT32 MediaId,
75 IN EFI_LBA Lba,
76 IN UINTN BufferSize,
77 OUT VOID *Buffer
78 )
79 /*++
80
81 Routine Description:
82
83 TODO: Add function description
84
85 Arguments:
86
87 This - TODO: add argument description
88 MediaId - TODO: add argument description
89 Lba - TODO: add argument description
90 BufferSize - TODO: add argument description
91 Buffer - TODO: add argument description
92
93 Returns:
94
95 TODO: add return values
96
97 --*/
98 ;
99
100 EFI_STATUS
101 EFIAPI
102 UnixBlockIoWriteBlocks (
103 IN EFI_BLOCK_IO_PROTOCOL *This,
104 IN UINT32 MediaId,
105 IN EFI_LBA Lba,
106 IN UINTN BufferSize,
107 IN VOID *Buffer
108 )
109 /*++
110
111 Routine Description:
112
113 TODO: Add function description
114
115 Arguments:
116
117 This - TODO: add argument description
118 MediaId - TODO: add argument description
119 Lba - TODO: add argument description
120 BufferSize - TODO: add argument description
121 Buffer - TODO: add argument description
122
123 Returns:
124
125 TODO: add return values
126
127 --*/
128 ;
129
130 EFI_STATUS
131 EFIAPI
132 UnixBlockIoFlushBlocks (
133 IN EFI_BLOCK_IO_PROTOCOL *This
134 )
135 /*++
136
137 Routine Description:
138
139 TODO: Add function description
140
141 Arguments:
142
143 This - TODO: add argument description
144
145 Returns:
146
147 TODO: add return values
148
149 --*/
150 ;
151
152 EFI_STATUS
153 EFIAPI
154 UnixBlockIoResetBlock (
155 IN EFI_BLOCK_IO_PROTOCOL *This,
156 IN BOOLEAN ExtendedVerification
157 )
158 /*++
159
160 Routine Description:
161
162 TODO: Add function description
163
164 Arguments:
165
166 This - TODO: add argument description
167 ExtendedVerification - TODO: add argument description
168
169 Returns:
170
171 TODO: add return values
172
173 --*/
174 ;
175
176 //
177 // Private Worker functions
178 //
179 EFI_STATUS
180 UnixBlockIoCreateMapping (
181 IN EFI_UNIX_IO_PROTOCOL *UnixIo,
182 IN EFI_HANDLE EfiDeviceHandle,
183 IN CHAR16 *Filename,
184 IN BOOLEAN ReadOnly,
185 IN BOOLEAN RemovableMedia,
186 IN UINTN NumberOfBlocks,
187 IN UINTN BlockSize
188 )
189 /*++
190
191 Routine Description:
192
193 TODO: Add function description
194
195 Arguments:
196
197 UnixIo - TODO: add argument description
198 EfiDeviceHandle - TODO: add argument description
199 Filename - TODO: add argument description
200 ReadOnly - TODO: add argument description
201 RemovableMedia - TODO: add argument description
202 NumberOfBlocks - TODO: add argument description
203 BlockSize - TODO: add argument description
204 DeviceType - TODO: add argument description
205
206 Returns:
207
208 TODO: add return values
209
210 --*/
211 ;
212
213 EFI_STATUS
214 UnixBlockIoReadWriteCommon (
215 IN UNIX_BLOCK_IO_PRIVATE *Private,
216 IN UINT32 MediaId,
217 IN EFI_LBA Lba,
218 IN UINTN BufferSize,
219 IN VOID *Buffer,
220 IN CHAR8 *CallerName
221 )
222 /*++
223
224 Routine Description:
225
226 TODO: Add function description
227
228 Arguments:
229
230 Private - TODO: add argument description
231 MediaId - TODO: add argument description
232 Lba - TODO: add argument description
233 BufferSize - TODO: add argument description
234 Buffer - TODO: add argument description
235 CallerName - TODO: add argument description
236
237 Returns:
238
239 TODO: add return values
240
241 --*/
242 ;
243
244 EFI_STATUS
245 UnixBlockIoError (
246 IN UNIX_BLOCK_IO_PRIVATE *Private
247 )
248 /*++
249
250 Routine Description:
251
252 TODO: Add function description
253
254 Arguments:
255
256 Private - TODO: add argument description
257
258 Returns:
259
260 TODO: add return values
261
262 --*/
263 ;
264
265 EFI_STATUS
266 UnixBlockIoOpenDevice (
267 UNIX_BLOCK_IO_PRIVATE *Private
268 )
269 /*++
270
271 Routine Description:
272
273 TODO: Add function description
274
275 Arguments:
276
277 Private - TODO: add argument description
278
279 Returns:
280
281 TODO: add return values
282
283 --*/
284 ;
285
286 CHAR16 *
287 GetNextElementPastTerminator (
288 IN CHAR16 *EnvironmentVariable,
289 IN CHAR16 Terminator
290 )
291 /*++
292
293 Routine Description:
294
295 TODO: Add function description
296
297 Arguments:
298
299 EnvironmentVariable - TODO: add argument description
300 Terminator - TODO: add argument description
301
302 Returns:
303
304 TODO: add return values
305
306 --*/
307 ;
308 EFI_DRIVER_BINDING_PROTOCOL gUnixBlockIoDriverBinding = {
309 UnixBlockIoDriverBindingSupported,
310 UnixBlockIoDriverBindingStart,
311 UnixBlockIoDriverBindingStop,
312 0xa,
313 NULL,
314 NULL
315 };
316
317 EFI_STATUS
318 EFIAPI
319 UnixBlockIoDriverBindingSupported (
320 IN EFI_DRIVER_BINDING_PROTOCOL *This,
321 IN EFI_HANDLE Handle,
322 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
323 )
324 /*++
325
326 Routine Description:
327
328 Arguments:
329
330 Returns:
331
332 None
333
334 --*/
335 // TODO: This - add argument and description to function comment
336 // TODO: Handle - add argument and description to function comment
337 // TODO: RemainingDevicePath - add argument and description to function comment
338 {
339 EFI_STATUS Status;
340 EFI_UNIX_IO_PROTOCOL *UnixIo;
341
342 //
343 // Open the IO Abstraction(s) needed to perform the supported test
344 //
345 Status = gBS->OpenProtocol (
346 Handle,
347 &gEfiUnixIoProtocolGuid,
348 (VOID **)&UnixIo,
349 This->DriverBindingHandle,
350 Handle,
351 EFI_OPEN_PROTOCOL_BY_DRIVER
352 );
353 if (EFI_ERROR (Status)) {
354 return Status;
355 }
356
357 //
358 // Make sure the UnixThunkProtocol is valid
359 //
360 Status = EFI_UNSUPPORTED;
361 if (UnixIo->UnixThunk->Signature == EFI_UNIX_THUNK_PROTOCOL_SIGNATURE) {
362
363 //
364 // Check the GUID to see if this is a handle type the driver supports
365 //
366 if (CompareGuid (UnixIo->TypeGuid, &gEfiUnixVirtualDisksGuid) ) {
367 Status = EFI_SUCCESS;
368 }
369 }
370
371 //
372 // Close the I/O Abstraction(s) used to perform the supported test
373 //
374 gBS->CloseProtocol (
375 Handle,
376 &gEfiUnixIoProtocolGuid,
377 This->DriverBindingHandle,
378 Handle
379 );
380 return Status;
381 }
382
383 EFI_STATUS
384 EFIAPI
385 UnixBlockIoDriverBindingStart (
386 IN EFI_DRIVER_BINDING_PROTOCOL *This,
387 IN EFI_HANDLE Handle,
388 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
389 )
390 /*++
391
392 Routine Description:
393
394 Arguments:
395
396 Returns:
397
398 None
399
400 --*/
401 // TODO: This - add argument and description to function comment
402 // TODO: Handle - add argument and description to function comment
403 // TODO: RemainingDevicePath - add argument and description to function comment
404 {
405 EFI_STATUS Status;
406 EFI_UNIX_IO_PROTOCOL *UnixIo;
407 CHAR16 Buffer[FILENAME_BUFFER_SIZE];
408 CHAR16 *Str;
409 BOOLEAN RemovableMedia;
410 BOOLEAN WriteProtected;
411 UINTN NumberOfBlocks;
412 UINTN BlockSize;
413 INTN i;
414
415 //
416 // Grab the protocols we need
417 //
418
419 Status = gBS->OpenProtocol (
420 Handle,
421 &gEfiUnixIoProtocolGuid,
422 (void *)&UnixIo,
423 This->DriverBindingHandle,
424 Handle,
425 EFI_OPEN_PROTOCOL_BY_DRIVER
426 );
427 if (EFI_ERROR (Status)) {
428 return Status;
429 }
430 //
431 // Set DiskType
432 //
433 if (!CompareGuid (UnixIo->TypeGuid, &gEfiUnixVirtualDisksGuid)) {
434 Status = EFI_UNSUPPORTED;
435 goto Done;
436 }
437
438 Status = EFI_NOT_FOUND;
439 // Extract filename.
440 Str = UnixIo->EnvString;
441 i = 0;
442 while (*Str && *Str != ':')
443 Buffer[i++] = *Str++;
444 Buffer[i] = 0;
445 if (*Str != ':') {
446 goto Done;
447 }
448
449 Str++;
450
451 RemovableMedia = FALSE;
452 WriteProtected = TRUE;
453 NumberOfBlocks = 0;
454 BlockSize = 512;
455 do {
456 if (*Str == 'R' || *Str == 'F') {
457 RemovableMedia = (BOOLEAN) (*Str == 'R');
458 Str++;
459 }
460 if (*Str == 'O' || *Str == 'W') {
461 WriteProtected = (BOOLEAN) (*Str == 'O');
462 Str++;
463 }
464 if (*Str == 0)
465 break;
466 if (*Str != ';')
467 goto Done;
468 Str++;
469
470 NumberOfBlocks = Atoi (Str);
471 Str = GetNextElementPastTerminator (Str, ';');
472 if (NumberOfBlocks == 0)
473 break;
474
475 BlockSize = Atoi (Str);
476 if (BlockSize != 0)
477 Str = GetNextElementPastTerminator (Str, ';');
478 } while (0);
479
480 //
481 // If we get here the variable is valid so do the work.
482 //
483 Status = UnixBlockIoCreateMapping (
484 UnixIo,
485 Handle,
486 Buffer,
487 WriteProtected,
488 RemovableMedia,
489 NumberOfBlocks,
490 BlockSize
491 );
492
493 Done:
494 if (EFI_ERROR (Status)) {
495 gBS->CloseProtocol (
496 Handle,
497 &gEfiUnixIoProtocolGuid,
498 This->DriverBindingHandle,
499 Handle
500 );
501 }
502
503 return Status;
504 }
505
506 EFI_STATUS
507 EFIAPI
508 UnixBlockIoDriverBindingStop (
509 IN EFI_DRIVER_BINDING_PROTOCOL *This,
510 IN EFI_HANDLE Handle,
511 IN UINTN NumberOfChildren,
512 IN EFI_HANDLE *ChildHandleBuffer
513 )
514 /*++
515
516 Routine Description:
517
518 TODO: Add function description
519
520 Arguments:
521
522 This - TODO: add argument description
523 Handle - TODO: add argument description
524 NumberOfChildren - TODO: add argument description
525 ChildHandleBuffer - TODO: add argument description
526
527 Returns:
528
529 EFI_UNSUPPORTED - TODO: Add description for return value
530
531 --*/
532 {
533 EFI_BLOCK_IO_PROTOCOL *BlockIo;
534 EFI_STATUS Status;
535 UNIX_BLOCK_IO_PRIVATE *Private;
536
537 //
538 // Get our context back
539 //
540 Status = gBS->OpenProtocol (
541 Handle,
542 &gEfiBlockIoProtocolGuid,
543 (void *)&BlockIo,
544 This->DriverBindingHandle,
545 Handle,
546 EFI_OPEN_PROTOCOL_GET_PROTOCOL
547 );
548 if (EFI_ERROR (Status)) {
549 return EFI_UNSUPPORTED;
550 }
551
552 Private = UNIX_BLOCK_IO_PRIVATE_DATA_FROM_THIS (BlockIo);
553
554 //
555 // BugBug: If we need to kick people off, we need to make Uninstall Close the handles.
556 // We could pass in our image handle or FLAG our open to be closed via
557 // Unistall (== to saying any CloseProtocol will close our open)
558 //
559 Status = gBS->UninstallMultipleProtocolInterfaces (
560 Private->EfiHandle,
561 &gEfiBlockIoProtocolGuid,
562 &Private->BlockIo,
563 NULL
564 );
565 if (!EFI_ERROR (Status)) {
566
567 Status = gBS->CloseProtocol (
568 Handle,
569 &gEfiUnixIoProtocolGuid,
570 This->DriverBindingHandle,
571 Handle
572 );
573
574 //
575 // Shut down our device
576 //
577 Private->UnixThunk->Close (Private->fd);
578
579 //
580 // Free our instance data
581 //
582 FreeUnicodeStringTable (Private->ControllerNameTable);
583
584 gBS->FreePool (Private);
585 }
586
587 return Status;
588 }
589
590 CHAR16 *
591 GetNextElementPastTerminator (
592 IN CHAR16 *EnvironmentVariable,
593 IN CHAR16 Terminator
594 )
595 /*++
596
597 Routine Description:
598
599 Worker function to parse environment variables.
600
601 Arguments:
602 EnvironmentVariable - Envirnment variable to parse.
603
604 Terminator - Terminator to parse for.
605
606 Returns:
607
608 Pointer to next eliment past the first occurence of Terminator or the '\0'
609 at the end of the string.
610
611 --*/
612 {
613 CHAR16 *Ptr;
614
615 for (Ptr = EnvironmentVariable; *Ptr != '\0'; Ptr++) {
616 if (*Ptr == Terminator) {
617 Ptr++;
618 break;
619 }
620 }
621
622 return Ptr;
623 }
624
625 EFI_STATUS
626 UnixBlockIoCreateMapping (
627 IN EFI_UNIX_IO_PROTOCOL *UnixIo,
628 IN EFI_HANDLE EfiDeviceHandle,
629 IN CHAR16 *Filename,
630 IN BOOLEAN ReadOnly,
631 IN BOOLEAN RemovableMedia,
632 IN UINTN NumberOfBlocks,
633 IN UINTN BlockSize
634 )
635 /*++
636
637 Routine Description:
638
639 TODO: Add function description
640
641 Arguments:
642
643 UnixIo - TODO: add argument description
644 EfiDeviceHandle - TODO: add argument description
645 Filename - TODO: add argument description
646 ReadOnly - TODO: add argument description
647 RemovableMedia - TODO: add argument description
648 NumberOfBlocks - TODO: add argument description
649 BlockSize - TODO: add argument description
650 DeviceType - TODO: add argument description
651
652 Returns:
653
654 TODO: add return values
655
656 --*/
657 {
658 EFI_STATUS Status;
659 EFI_BLOCK_IO_PROTOCOL *BlockIo;
660 UNIX_BLOCK_IO_PRIVATE *Private;
661 UINTN Index;
662
663 Status = gBS->AllocatePool (
664 EfiBootServicesData,
665 sizeof (UNIX_BLOCK_IO_PRIVATE),
666 (void *)&Private
667 );
668 ASSERT_EFI_ERROR (Status);
669
670 EfiInitializeLock (&Private->Lock, TPL_NOTIFY);
671
672 Private->UnixThunk = UnixIo->UnixThunk;
673
674 Private->Signature = UNIX_BLOCK_IO_PRIVATE_SIGNATURE;
675 Private->LastBlock = NumberOfBlocks - 1;
676 Private->BlockSize = BlockSize;
677
678 for (Index = 0; Filename[Index] != 0; Index++) {
679 Private->Filename[Index] = Filename[Index];
680 }
681
682 Private->Filename[Index] = 0;
683
684 Private->Mode = (ReadOnly ? O_RDONLY : O_RDWR);
685
686 Private->NumberOfBlocks = NumberOfBlocks;
687 Private->fd = -1;
688
689 Private->ControllerNameTable = NULL;
690
691 AddUnicodeString (
692 "eng",
693 gUnixBlockIoComponentName.SupportedLanguages,
694 &Private->ControllerNameTable,
695 Filename
696 );
697
698 BlockIo = &Private->BlockIo;
699 BlockIo->Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
700 BlockIo->Media = &Private->Media;
701 BlockIo->Media->BlockSize = Private->BlockSize;
702 BlockIo->Media->LastBlock = Private->NumberOfBlocks - 1;
703 BlockIo->Media->MediaId = 0;;
704
705 BlockIo->Reset = UnixBlockIoResetBlock;
706 BlockIo->ReadBlocks = UnixBlockIoReadBlocks;
707 BlockIo->WriteBlocks = UnixBlockIoWriteBlocks;
708 BlockIo->FlushBlocks = UnixBlockIoFlushBlocks;
709
710 BlockIo->Media->ReadOnly = ReadOnly;
711 BlockIo->Media->RemovableMedia = RemovableMedia;
712 BlockIo->Media->LogicalPartition = FALSE;
713 BlockIo->Media->MediaPresent = TRUE;
714 BlockIo->Media->WriteCaching = FALSE;
715
716 BlockIo->Media->IoAlign = 1;
717
718 Private->EfiHandle = EfiDeviceHandle;
719 Status = UnixBlockIoOpenDevice (Private);
720 if (!EFI_ERROR (Status)) {
721
722 Status = gBS->InstallMultipleProtocolInterfaces (
723 &Private->EfiHandle,
724 &gEfiBlockIoProtocolGuid,
725 &Private->BlockIo,
726 NULL
727 );
728 if (EFI_ERROR (Status)) {
729 FreeUnicodeStringTable (Private->ControllerNameTable);
730 gBS->FreePool (Private);
731 }
732
733 DEBUG ((EFI_D_ERROR, "BlockDevice added: %s\n", Filename));
734 }
735
736 return Status;
737 }
738
739 EFI_STATUS
740 UnixBlockIoOpenDevice (
741 UNIX_BLOCK_IO_PRIVATE *Private
742 )
743 /*++
744
745 Routine Description:
746
747 TODO: Add function description
748
749 Arguments:
750
751 Private - TODO: add argument description
752
753 Returns:
754
755 TODO: add return values
756
757 --*/
758 {
759 EFI_STATUS Status;
760 UINT64 FileSize;
761 UINT64 EndOfFile;
762 EFI_BLOCK_IO_PROTOCOL *BlockIo;
763
764 BlockIo = &Private->BlockIo;
765 EfiAcquireLock (&Private->Lock);
766
767 //
768 // If the device is already opened, close it
769 //
770 if (Private->fd >= 0) {
771 BlockIo->Reset (BlockIo, FALSE);
772 }
773
774 //
775 // Open the device
776 //
777 Private->fd = Private->UnixThunk->Open
778 (Private->Filename, Private->Mode, 0644);
779
780 if (Private->fd < 0) {
781 DEBUG ((EFI_D_INFO, "PlOpenBlock: Could not open %s\n",
782 Private->Filename));
783 BlockIo->Media->MediaPresent = FALSE;
784 Status = EFI_NO_MEDIA;
785 goto Done;
786 }
787
788 if (!BlockIo->Media->MediaPresent) {
789 //
790 // BugBug: try to emulate if a CD appears - notify drivers to check it out
791 //
792 BlockIo->Media->MediaPresent = TRUE;
793 EfiReleaseLock (&Private->Lock);
794 EfiAcquireLock (&Private->Lock);
795 }
796
797 //
798 // get the size of the file
799 //
800 Status = SetFilePointer64 (Private, 0, &FileSize, SEEK_END);
801
802 if (EFI_ERROR (Status)) {
803 FileSize = MultU64x32 (Private->NumberOfBlocks, Private->BlockSize);
804 DEBUG ((EFI_D_ERROR, "PlOpenBlock: Could not get filesize of %s\n", Private->Filename));
805 Status = EFI_UNSUPPORTED;
806 goto Done;
807 }
808
809 if (Private->NumberOfBlocks == 0) {
810 Private->NumberOfBlocks = DivU64x32 (FileSize, Private->BlockSize);
811 }
812
813 EndOfFile = MultU64x32 (Private->NumberOfBlocks, Private->BlockSize);
814
815 if (FileSize != EndOfFile) {
816 //
817 // file is not the proper size, change it
818 //
819 DEBUG ((EFI_D_INIT, "PlOpenBlock: Initializing block device: %a\n", Private->Filename));
820
821 //
822 // first set it to 0
823 //
824 Private->UnixThunk->FTruncate (Private->fd, 0);
825
826 //
827 // then set it to the needed file size (OS will zero fill it)
828 //
829 Private->UnixThunk->FTruncate (Private->fd, EndOfFile);
830 }
831
832 DEBUG ((EFI_D_INIT, "%HPlOpenBlock: opened %s%N\n", Private->Filename));
833 Status = EFI_SUCCESS;
834
835 Done:
836 if (EFI_ERROR (Status)) {
837 if (Private->fd >= 0) {
838 BlockIo->Reset (BlockIo, FALSE);
839 }
840 }
841
842 EfiReleaseLock (&Private->Lock);
843 return Status;
844 }
845
846 EFI_STATUS
847 UnixBlockIoError (
848 IN UNIX_BLOCK_IO_PRIVATE *Private
849 )
850 /*++
851
852 Routine Description:
853
854 TODO: Add function description
855
856 Arguments:
857
858 Private - TODO: add argument description
859
860 Returns:
861
862 TODO: add return values
863
864 --*/
865 {
866 return EFI_DEVICE_ERROR;
867
868 #if 0
869 EFI_BLOCK_IO_PROTOCOL *BlockIo;
870 EFI_STATUS Status;
871 BOOLEAN ReinstallBlockIoFlag;
872
873
874 BlockIo = &Private->BlockIo;
875
876 switch (Private->UnixThunk->GetLastError ()) {
877
878 case ERROR_NOT_READY:
879 Status = EFI_NO_MEDIA;
880 BlockIo->Media->ReadOnly = FALSE;
881 BlockIo->Media->MediaPresent = FALSE;
882 ReinstallBlockIoFlag = FALSE;
883 break;
884
885 case ERROR_WRONG_DISK:
886 BlockIo->Media->ReadOnly = FALSE;
887 BlockIo->Media->MediaPresent = TRUE;
888 BlockIo->Media->MediaId += 1;
889 ReinstallBlockIoFlag = TRUE;
890 Status = EFI_MEDIA_CHANGED;
891 break;
892
893 case ERROR_WRITE_PROTECT:
894 BlockIo->Media->ReadOnly = TRUE;
895 ReinstallBlockIoFlag = FALSE;
896 Status = EFI_WRITE_PROTECTED;
897 break;
898
899 default:
900 ReinstallBlockIoFlag = FALSE;
901 Status = EFI_DEVICE_ERROR;
902 break;
903 }
904
905 if (ReinstallBlockIoFlag) {
906 BlockIo->Reset (BlockIo, FALSE);
907
908 gBS->ReinstallProtocolInterface (
909 Private->EfiHandle,
910 &gEfiBlockIoProtocolGuid,
911 BlockIo,
912 BlockIo
913 );
914 }
915
916 return Status;
917 #endif
918 }
919
920 EFI_STATUS
921 UnixBlockIoReadWriteCommon (
922 IN UNIX_BLOCK_IO_PRIVATE *Private,
923 IN UINT32 MediaId,
924 IN EFI_LBA Lba,
925 IN UINTN BufferSize,
926 IN VOID *Buffer,
927 IN CHAR8 *CallerName
928 )
929 /*++
930
931 Routine Description:
932
933 TODO: Add function description
934
935 Arguments:
936
937 Private - TODO: add argument description
938 MediaId - TODO: add argument description
939 Lba - TODO: add argument description
940 BufferSize - TODO: add argument description
941 Buffer - TODO: add argument description
942 CallerName - TODO: add argument description
943
944 Returns:
945
946 EFI_NO_MEDIA - TODO: Add description for return value
947 EFI_MEDIA_CHANGED - TODO: Add description for return value
948 EFI_INVALID_PARAMETER - TODO: Add description for return value
949 EFI_SUCCESS - TODO: Add description for return value
950 EFI_BAD_BUFFER_SIZE - TODO: Add description for return value
951 EFI_INVALID_PARAMETER - TODO: Add description for return value
952 EFI_SUCCESS - TODO: Add description for return value
953
954 --*/
955 {
956 EFI_STATUS Status;
957 UINTN BlockSize;
958 UINT64 LastBlock;
959 INT64 DistanceToMove;
960 UINT64 DistanceMoved;
961
962 if (Private->fd < 0) {
963 Status = UnixBlockIoOpenDevice (Private);
964 if (EFI_ERROR (Status)) {
965 return Status;
966 }
967 }
968
969 if (!Private->Media.MediaPresent) {
970 DEBUG ((EFI_D_INIT, "%s: No Media\n", CallerName));
971 return EFI_NO_MEDIA;
972 }
973
974 if (Private->Media.MediaId != MediaId) {
975 return EFI_MEDIA_CHANGED;
976 }
977
978 if ((UINT32) Buffer % Private->Media.IoAlign != 0) {
979 return EFI_INVALID_PARAMETER;
980 }
981
982 //
983 // Verify buffer size
984 //
985 BlockSize = Private->BlockSize;
986 if (BufferSize == 0) {
987 DEBUG ((EFI_D_INIT, "%s: Zero length read\n", CallerName));
988 return EFI_SUCCESS;
989 }
990
991 if ((BufferSize % BlockSize) != 0) {
992 DEBUG ((EFI_D_INIT, "%s: Invalid read size\n", CallerName));
993 return EFI_BAD_BUFFER_SIZE;
994 }
995
996 LastBlock = Lba + (BufferSize / BlockSize) - 1;
997 if (LastBlock > Private->LastBlock) {
998 DEBUG ((EFI_D_INIT, "ReadBlocks: Attempted to read off end of device\n"));
999 return EFI_INVALID_PARAMETER;
1000 }
1001 //
1002 // Seek to End of File
1003 //
1004 DistanceToMove = MultU64x32 (Lba, BlockSize);
1005 Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, SEEK_SET);
1006
1007 if (EFI_ERROR (Status)) {
1008 DEBUG ((EFI_D_INIT, "WriteBlocks: SetFilePointer failed\n"));
1009 return UnixBlockIoError (Private);
1010 }
1011
1012 return EFI_SUCCESS;
1013 }
1014
1015 EFI_STATUS
1016 EFIAPI
1017 UnixBlockIoReadBlocks (
1018 IN EFI_BLOCK_IO_PROTOCOL *This,
1019 IN UINT32 MediaId,
1020 IN EFI_LBA Lba,
1021 IN UINTN BufferSize,
1022 OUT VOID *Buffer
1023 )
1024 /*++
1025
1026 Routine Description:
1027 Read BufferSize bytes from Lba into Buffer.
1028
1029 Arguments:
1030 This - Protocol instance pointer.
1031 MediaId - Id of the media, changes every time the media is replaced.
1032 Lba - The starting Logical Block Address to read from
1033 BufferSize - Size of Buffer, must be a multiple of device block size.
1034 Buffer - Buffer containing read data
1035
1036 Returns:
1037 EFI_SUCCESS - The data was read correctly from the device.
1038 EFI_DEVICE_ERROR - The device reported an error while performing the read.
1039 EFI_NO_MEDIA - There is no media in the device.
1040 EFI_MEDIA_CHANGED - The MediaId does not matched the current device.
1041 EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the
1042 device.
1043 EFI_INVALID_PARAMETER - The read request contains device addresses that are not
1044 valid for the device.
1045
1046 --*/
1047 {
1048 UNIX_BLOCK_IO_PRIVATE *Private;
1049 ssize_t len;
1050 EFI_STATUS Status;
1051 EFI_TPL OldTpl;
1052
1053 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1054
1055 Private = UNIX_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
1056
1057 Status = UnixBlockIoReadWriteCommon (Private, MediaId, Lba, BufferSize, Buffer, "UnixReadBlocks");
1058 if (EFI_ERROR (Status)) {
1059 goto Done;
1060 }
1061
1062 len = Private->UnixThunk->Read (Private->fd, Buffer, BufferSize);
1063 if (len != BufferSize) {
1064 DEBUG ((EFI_D_INIT, "ReadBlocks: ReadFile failed.\n"));
1065 Status = UnixBlockIoError (Private);
1066 goto Done;
1067 }
1068
1069 //
1070 // If we wrote then media is present.
1071 //
1072 This->Media->MediaPresent = TRUE;
1073 Status = EFI_SUCCESS;
1074
1075 Done:
1076 gBS->RestoreTPL (OldTpl);
1077 return Status;
1078 }
1079
1080 EFI_STATUS
1081 EFIAPI
1082 UnixBlockIoWriteBlocks (
1083 IN EFI_BLOCK_IO_PROTOCOL *This,
1084 IN UINT32 MediaId,
1085 IN EFI_LBA Lba,
1086 IN UINTN BufferSize,
1087 IN VOID *Buffer
1088 )
1089 /*++
1090
1091 Routine Description:
1092 Write BufferSize bytes from Lba into Buffer.
1093
1094 Arguments:
1095 This - Protocol instance pointer.
1096 MediaId - Id of the media, changes every time the media is replaced.
1097 Lba - The starting Logical Block Address to read from
1098 BufferSize - Size of Buffer, must be a multiple of device block size.
1099 Buffer - Buffer containing read data
1100
1101 Returns:
1102 EFI_SUCCESS - The data was written correctly to the device.
1103 EFI_WRITE_PROTECTED - The device can not be written to.
1104 EFI_DEVICE_ERROR - The device reported an error while performing the write.
1105 EFI_NO_MEDIA - There is no media in the device.
1106 EFI_MEDIA_CHNAGED - The MediaId does not matched the current device.
1107 EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the
1108 device.
1109 EFI_INVALID_PARAMETER - The write request contains a LBA that is not
1110 valid for the device.
1111
1112 --*/
1113 {
1114 UNIX_BLOCK_IO_PRIVATE *Private;
1115 ssize_t len;
1116 EFI_STATUS Status;
1117 EFI_TPL OldTpl;
1118
1119 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1120
1121 Private = UNIX_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
1122
1123 Status = UnixBlockIoReadWriteCommon (Private, MediaId, Lba, BufferSize, Buffer, "UnixWriteBlocks");
1124 if (EFI_ERROR (Status)) {
1125 goto Done;
1126 }
1127
1128 len = Private->UnixThunk->Write (Private->fd, Buffer, BufferSize);
1129 if (len != BufferSize) {
1130 DEBUG ((EFI_D_INIT, "ReadBlocks: WriteFile failed.\n"));
1131 Status = UnixBlockIoError (Private);
1132 goto Done;
1133 }
1134
1135 //
1136 // If the write succeeded, we are not write protected and media is present.
1137 //
1138 This->Media->MediaPresent = TRUE;
1139 This->Media->ReadOnly = FALSE;
1140 Status = EFI_SUCCESS;
1141
1142 Done:
1143 gBS->RestoreTPL (OldTpl);
1144 return Status;
1145 }
1146
1147 EFI_STATUS
1148 EFIAPI
1149 UnixBlockIoFlushBlocks (
1150 IN EFI_BLOCK_IO_PROTOCOL *This
1151 )
1152 /*++
1153
1154 Routine Description:
1155 Flush the Block Device.
1156
1157 Arguments:
1158 This - Protocol instance pointer.
1159
1160 Returns:
1161 EFI_SUCCESS - All outstanding data was written to the device
1162 EFI_DEVICE_ERROR - The device reported an error while writting back the data
1163 EFI_NO_MEDIA - There is no media in the device.
1164
1165 --*/
1166 {
1167 return EFI_SUCCESS;
1168 }
1169
1170 EFI_STATUS
1171 EFIAPI
1172 UnixBlockIoResetBlock (
1173 IN EFI_BLOCK_IO_PROTOCOL *This,
1174 IN BOOLEAN ExtendedVerification
1175 )
1176 /*++
1177
1178 Routine Description:
1179 Reset the Block Device.
1180
1181 Arguments:
1182 This - Protocol instance pointer.
1183 ExtendedVerification - Driver may perform diagnostics on reset.
1184
1185 Returns:
1186 EFI_SUCCESS - The device was reset.
1187 EFI_DEVICE_ERROR - The device is not functioning properly and could
1188 not be reset.
1189
1190 --*/
1191 {
1192 UNIX_BLOCK_IO_PRIVATE *Private;
1193 EFI_TPL OldTpl;
1194
1195 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1196
1197 Private = UNIX_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
1198
1199 if (Private->fd >= 0) {
1200 Private->UnixThunk->Close (Private->fd);
1201 Private->fd = -1;
1202 }
1203
1204 gBS->RestoreTPL (OldTpl);
1205
1206 return EFI_SUCCESS;
1207 }
1208
1209 UINTN
1210 Atoi (
1211 CHAR16 *String
1212 )
1213 /*++
1214
1215 Routine Description:
1216
1217 Convert a unicode string to a UINTN
1218
1219 Arguments:
1220
1221 String - Unicode string.
1222
1223 Returns:
1224
1225 UINTN of the number represented by String.
1226
1227 --*/
1228 {
1229 UINTN Number;
1230 CHAR16 *Str;
1231
1232 //
1233 // skip preceeding white space
1234 //
1235 Str = String;
1236 while ((*Str) && (*Str == ' ')) {
1237 Str++;
1238 }
1239 //
1240 // Convert ot a Number
1241 //
1242 Number = 0;
1243 while (*Str != '\0') {
1244 if ((*Str >= '0') && (*Str <= '9')) {
1245 Number = (Number * 10) +*Str - '0';
1246 } else {
1247 break;
1248 }
1249
1250 Str++;
1251 }
1252
1253 return Number;
1254 }
1255
1256 EFI_STATUS
1257 SetFilePointer64 (
1258 IN UNIX_BLOCK_IO_PRIVATE *Private,
1259 IN INT64 DistanceToMove,
1260 OUT UINT64 *NewFilePointer,
1261 IN INTN MoveMethod
1262 )
1263 /*++
1264
1265 This function extends the capability of SetFilePointer to accept 64 bit parameters
1266
1267 --*/
1268 // TODO: function comment is missing 'Routine Description:'
1269 // TODO: function comment is missing 'Arguments:'
1270 // TODO: function comment is missing 'Returns:'
1271 // TODO: Private - add argument and description to function comment
1272 // TODO: DistanceToMove - add argument and description to function comment
1273 // TODO: NewFilePointer - add argument and description to function comment
1274 // TODO: MoveMethod - add argument and description to function comment
1275 {
1276 EFI_STATUS Status;
1277 off_t res;
1278
1279 Status = EFI_SUCCESS;
1280 res = Private->UnixThunk->Lseek(Private->fd, DistanceToMove, MoveMethod);
1281 if (res == -1) {
1282 Status = EFI_INVALID_PARAMETER;
1283 }
1284
1285 if (NewFilePointer != NULL) {
1286 *NewFilePointer = res;
1287 }
1288
1289 return Status;
1290 }