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