]> git.proxmox.com Git - mirror_edk2.git/blob - InOsEmuPkg/Unix/Sec/BlockIo.c
3fc1d3f9aaeb8669b4e5425b1976408a36b69f4e
[mirror_edk2.git] / InOsEmuPkg / Unix / Sec / BlockIo.c
1 /**@file
2
3 Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR>
4 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_EMU_VIRTUAL_DISKS =
36 <F | R><O | W>;<block count>;<block size>[!...]
37
38 EFI_EMU_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_EMU_VIRTUAL_DISKS=FW;40960;512
46
47 A 1.44MB emulated floppy with a block size of 1024 would look like:
48 EFI_EMU_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_EMU_PHYSICAL_DISKS=B:RW;245760;512
54
55 Thus a standard CD-ROM floppy would look like:
56 EFI_EMU_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 EFI_STATUS
81 EFIAPI
82 UnixBlockIoWriteBlocks (
83 IN EFI_BLOCK_IO_PROTOCOL *This,
84 IN UINT32 MediaId,
85 IN EFI_LBA Lba,
86 IN UINTN BufferSize,
87 IN VOID *Buffer
88 );
89
90 EFI_STATUS
91 EFIAPI
92 UnixBlockIoFlushBlocks (
93 IN EFI_BLOCK_IO_PROTOCOL *This
94 );
95
96 EFI_STATUS
97 EFIAPI
98 UnixBlockIoResetBlock (
99 IN EFI_BLOCK_IO_PROTOCOL *This,
100 IN BOOLEAN ExtendedVerification
101 );
102
103 //
104 // Private Worker functions
105 //
106 EFI_STATUS
107 UnixBlockIoCreateMapping (
108 IN EMU_IO_THUNK_PROTOCOL *EmuIoThunk,
109 IN EFI_HANDLE EfiDeviceHandle,
110 IN CHAR16 *Filename,
111 IN BOOLEAN ReadOnly,
112 IN BOOLEAN RemovableMedia,
113 IN UINTN NumberOfBlocks,
114 IN UINTN BlockSize
115 );
116
117 EFI_STATUS
118 UnixBlockIoReadWriteCommon (
119 IN EMU_BLOCK_IO_PRIVATE *Private,
120 IN UINT32 MediaId,
121 IN EFI_LBA Lba,
122 IN UINTN BufferSize,
123 IN VOID *Buffer,
124 IN CHAR8 *CallerName
125 );
126
127 EFI_STATUS
128 UnixBlockIoError (
129 IN EMU_BLOCK_IO_PRIVATE *Private
130 );
131
132 EFI_STATUS
133 UnixBlockIoOpenDevice (
134 EMU_BLOCK_IO_PRIVATE *Private
135 );
136
137 CHAR16 *
138 GetNextElementPastTerminator (
139 IN CHAR16 *EnvironmentVariable,
140 IN CHAR16 Terminator
141 );
142
143
144
145 EFI_DRIVER_BINDING_PROTOCOL gUnixBlockIoDriverBinding = {
146 UnixBlockIoDriverBindingSupported,
147 UnixBlockIoDriverBindingStart,
148 UnixBlockIoDriverBindingStop,
149 0xa,
150 NULL,
151 NULL
152 };
153
154 /**
155 The user Entry Point for module UnixBlockIo. The user code starts with this function.
156
157 @param[in] ImageHandle The firmware allocated handle for the EFI image.
158 @param[in] SystemTable A pointer to the EFI System Table.
159
160 @retval EFI_SUCCESS The entry point is executed successfully.
161 @retval other Some error occurs when executing this entry point.
162
163 **/
164 EFI_STATUS
165 EFIAPI
166 InitializeUnixBlockIo(
167 IN EFI_HANDLE ImageHandle,
168 IN EFI_SYSTEM_TABLE *SystemTable
169 )
170 {
171 EFI_STATUS Status;
172
173 Status = EfiLibInstallAllDriverProtocols2 (
174 ImageHandle,
175 SystemTable,
176 &gUnixBlockIoDriverBinding,
177 ImageHandle,
178 &gUnixBlockIoComponentName,
179 &gUnixBlockIoComponentName2,
180 NULL,
181 &gUnixBlockIoDriverDiagnostics,
182 &gUnixBlockIoDriverDiagnostics2
183 );
184 ASSERT_EFI_ERROR (Status);
185
186
187 return Status;
188 }
189
190 EFI_STATUS
191 EFIAPI
192 UnixBlockIoDriverBindingSupported (
193 IN EFI_DRIVER_BINDING_PROTOCOL *This,
194 IN EFI_HANDLE Handle,
195 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
196 )
197 /*++
198
199 Routine Description:
200
201 Arguments:
202
203 Returns:
204
205 None
206
207 **/
208 {
209 EFI_STATUS Status;
210 EMU_IO_THUNK_PROTOCOL *EmuIoThunk;
211
212 //
213 // Open the IO Abstraction(s) needed to perform the supported test
214 //
215 Status = gBS->OpenProtocol (
216 Handle,
217 &gEmuIoThunkProtocolGuid,
218 (VOID **)&EmuIoThunk,
219 This->DriverBindingHandle,
220 Handle,
221 EFI_OPEN_PROTOCOL_BY_DRIVER
222 );
223 if (EFI_ERROR (Status)) {
224 return Status;
225 }
226
227 //
228 // Make sure the UnixThunkProtocol is valid
229 //
230 Status = EFI_UNSUPPORTED;
231 if (EmuIoThunk->UnixThunk->Signature == EFI_EMU_THUNK_PROTOCOL_SIGNATURE) {
232
233 //
234 // Check the GUID to see if this is a handle type the driver supports
235 //
236 if (CompareGuid (EmuIoThunk->TypeGuid, &gEfiUnixVirtualDisksGuid) ) {
237 Status = EFI_SUCCESS;
238 }
239 }
240
241 //
242 // Close the I/O Abstraction(s) used to perform the supported test
243 //
244 gBS->CloseProtocol (
245 Handle,
246 &gEmuIoThunkProtocolGuid,
247 This->DriverBindingHandle,
248 Handle
249 );
250 return Status;
251 }
252
253 EFI_STATUS
254 EFIAPI
255 UnixBlockIoDriverBindingStart (
256 IN EFI_DRIVER_BINDING_PROTOCOL *This,
257 IN EFI_HANDLE Handle,
258 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
259 )
260 /*++
261
262 Routine Description:
263
264 Arguments:
265
266 Returns:
267
268 None
269
270 **/
271 {
272 EFI_STATUS Status;
273 EMU_IO_THUNK_PROTOCOL *EmuIoThunk;
274 CHAR16 Buffer[FILENAME_BUFFER_SIZE];
275 CHAR16 *Str;
276 BOOLEAN RemovableMedia;
277 BOOLEAN WriteProtected;
278 UINTN NumberOfBlocks;
279 UINTN BlockSize;
280 INTN i;
281
282 //
283 // Grab the protocols we need
284 //
285
286 Status = gBS->OpenProtocol (
287 Handle,
288 &gEmuIoThunkProtocolGuid,
289 (void *)&EmuIoThunk,
290 This->DriverBindingHandle,
291 Handle,
292 EFI_OPEN_PROTOCOL_BY_DRIVER
293 );
294 if (EFI_ERROR (Status)) {
295 return Status;
296 }
297 //
298 // Set DiskType
299 //
300 if (!CompareGuid (EmuIoThunk->TypeGuid, &gEfiUnixVirtualDisksGuid)) {
301 Status = EFI_UNSUPPORTED;
302 goto Done;
303 }
304
305 Status = EFI_NOT_FOUND;
306 // Extract filename.
307 Str = EmuIoThunk->EnvString;
308 i = 0;
309 while (*Str && *Str != ':')
310 Buffer[i++] = *Str++;
311 Buffer[i] = 0;
312 if (*Str != ':') {
313 goto Done;
314 }
315
316 Str++;
317
318 RemovableMedia = FALSE;
319 WriteProtected = TRUE;
320 NumberOfBlocks = 0;
321 BlockSize = 512;
322 do {
323 if (*Str == 'R' || *Str == 'F') {
324 RemovableMedia = (BOOLEAN) (*Str == 'R');
325 Str++;
326 }
327 if (*Str == 'O' || *Str == 'W') {
328 WriteProtected = (BOOLEAN) (*Str == 'O');
329 Str++;
330 }
331 if (*Str == 0)
332 break;
333 if (*Str != ';')
334 goto Done;
335 Str++;
336
337 NumberOfBlocks = Atoi (Str);
338 Str = GetNextElementPastTerminator (Str, ';');
339 if (NumberOfBlocks == 0)
340 break;
341
342 BlockSize = Atoi (Str);
343 if (BlockSize != 0)
344 Str = GetNextElementPastTerminator (Str, ';');
345 } while (0);
346
347 //
348 // If we get here the variable is valid so do the work.
349 //
350 Status = UnixBlockIoCreateMapping (
351 EmuIoThunk,
352 Handle,
353 Buffer,
354 WriteProtected,
355 RemovableMedia,
356 NumberOfBlocks,
357 BlockSize
358 );
359
360 Done:
361 if (EFI_ERROR (Status)) {
362 gBS->CloseProtocol (
363 Handle,
364 &gEmuIoThunkProtocolGuid,
365 This->DriverBindingHandle,
366 Handle
367 );
368 }
369
370 return Status;
371 }
372
373 EFI_STATUS
374 EFIAPI
375 UnixBlockIoDriverBindingStop (
376 IN EFI_DRIVER_BINDING_PROTOCOL *This,
377 IN EFI_HANDLE Handle,
378 IN UINTN NumberOfChildren,
379 IN EFI_HANDLE *ChildHandleBuffer
380 )
381 {
382 EFI_BLOCK_IO_PROTOCOL *BlockIo;
383 EFI_STATUS Status;
384 EMU_BLOCK_IO_PRIVATE *Private;
385
386 //
387 // Get our context back
388 //
389 Status = gBS->OpenProtocol (
390 Handle,
391 &gEfiBlockIoProtocolGuid,
392 (void *)&BlockIo,
393 This->DriverBindingHandle,
394 Handle,
395 EFI_OPEN_PROTOCOL_GET_PROTOCOL
396 );
397 if (EFI_ERROR (Status)) {
398 return EFI_UNSUPPORTED;
399 }
400
401 Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (BlockIo);
402
403 //
404 // BugBug: If we need to kick people off, we need to make Uninstall Close the handles.
405 // We could pass in our image handle or FLAG our open to be closed via
406 // Unistall (== to saying any CloseProtocol will close our open)
407 //
408 Status = gBS->UninstallMultipleProtocolInterfaces (
409 Private->EfiHandle,
410 &gEfiBlockIoProtocolGuid,
411 &Private->BlockIo,
412 NULL
413 );
414 if (!EFI_ERROR (Status)) {
415
416 Status = gBS->CloseProtocol (
417 Handle,
418 &gEmuIoThunkProtocolGuid,
419 This->DriverBindingHandle,
420 Handle
421 );
422
423 //
424 // Shut down our device
425 //
426 Private->UnixThunk->Close (Private->fd);
427
428 //
429 // Free our instance data
430 //
431 FreeUnicodeStringTable (Private->ControllerNameTable);
432
433 gBS->FreePool (Private);
434 }
435
436 return Status;
437 }
438
439 CHAR16 *
440 GetNextElementPastTerminator (
441 IN CHAR16 *EnvironmentVariable,
442 IN CHAR16 Terminator
443 )
444 /*++
445
446 Routine Description:
447
448 Worker function to parse environment variables.
449
450 Arguments:
451 EnvironmentVariable - Envirnment variable to parse.
452
453 Terminator - Terminator to parse for.
454
455 Returns:
456
457 Pointer to next eliment past the first occurence of Terminator or the '\0'
458 at the end of the string.
459
460 **/
461 {
462 CHAR16 *Ptr;
463
464 for (Ptr = EnvironmentVariable; *Ptr != '\0'; Ptr++) {
465 if (*Ptr == Terminator) {
466 Ptr++;
467 break;
468 }
469 }
470
471 return Ptr;
472 }
473
474 EFI_STATUS
475 UnixBlockIoCreateMapping (
476 IN EMU_IO_THUNK_PROTOCOL *EmuIoThunk,
477 IN EFI_HANDLE EfiDeviceHandle,
478 IN CHAR16 *Filename,
479 IN BOOLEAN ReadOnly,
480 IN BOOLEAN RemovableMedia,
481 IN UINTN NumberOfBlocks,
482 IN UINTN BlockSize
483 )
484 {
485 EFI_STATUS Status;
486 EFI_BLOCK_IO_PROTOCOL *BlockIo;
487 EMU_BLOCK_IO_PRIVATE *Private;
488 UINTN Index;
489
490 Status = gBS->AllocatePool (
491 EfiBootServicesData,
492 sizeof (EMU_BLOCK_IO_PRIVATE),
493 (void *)&Private
494 );
495 ASSERT_EFI_ERROR (Status);
496
497 EfiInitializeLock (&Private->Lock, TPL_NOTIFY);
498
499 Private->UnixThunk = EmuIoThunk->UnixThunk;
500
501 Private->Signature = EMU_BLOCK_IO_PRIVATE_SIGNATURE;
502 Private->LastBlock = NumberOfBlocks - 1;
503 Private->BlockSize = BlockSize;
504
505 for (Index = 0; Filename[Index] != 0; Index++) {
506 Private->Filename[Index] = Filename[Index];
507 }
508
509 Private->Filename[Index] = 0;
510
511 Private->Mode = (ReadOnly ? O_RDONLY : O_RDWR);
512
513 Private->NumberOfBlocks = NumberOfBlocks;
514 Private->fd = -1;
515
516 Private->ControllerNameTable = NULL;
517
518 AddUnicodeString (
519 "eng",
520 gUnixBlockIoComponentName.SupportedLanguages,
521 &Private->ControllerNameTable,
522 Filename
523 );
524
525 BlockIo = &Private->BlockIo;
526 BlockIo->Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
527 BlockIo->Media = &Private->Media;
528 BlockIo->Media->BlockSize = Private->BlockSize;
529 BlockIo->Media->LastBlock = Private->NumberOfBlocks - 1;
530 BlockIo->Media->MediaId = 0;;
531
532 BlockIo->Reset = UnixBlockIoResetBlock;
533 BlockIo->ReadBlocks = UnixBlockIoReadBlocks;
534 BlockIo->WriteBlocks = UnixBlockIoWriteBlocks;
535 BlockIo->FlushBlocks = UnixBlockIoFlushBlocks;
536
537 BlockIo->Media->ReadOnly = ReadOnly;
538 BlockIo->Media->RemovableMedia = RemovableMedia;
539 BlockIo->Media->LogicalPartition = FALSE;
540 BlockIo->Media->MediaPresent = TRUE;
541 BlockIo->Media->WriteCaching = FALSE;
542
543 BlockIo->Media->IoAlign = 1;
544
545 Private->EfiHandle = EfiDeviceHandle;
546 Status = UnixBlockIoOpenDevice (Private);
547 if (!EFI_ERROR (Status)) {
548
549 Status = gBS->InstallMultipleProtocolInterfaces (
550 &Private->EfiHandle,
551 &gEfiBlockIoProtocolGuid,
552 &Private->BlockIo,
553 NULL
554 );
555 if (EFI_ERROR (Status)) {
556 FreeUnicodeStringTable (Private->ControllerNameTable);
557 gBS->FreePool (Private);
558 }
559
560 DEBUG ((EFI_D_ERROR, "BlockDevice added: %s\n", Filename));
561 }
562
563 return Status;
564 }
565
566 EFI_STATUS
567 UnixBlockIoOpenDevice (
568 EMU_BLOCK_IO_PRIVATE *Private
569 )
570 {
571 EFI_STATUS Status;
572 UINT64 FileSize;
573 UINT64 EndOfFile;
574 EFI_BLOCK_IO_PROTOCOL *BlockIo;
575
576 BlockIo = &Private->BlockIo;
577 EfiAcquireLock (&Private->Lock);
578
579 //
580 // If the device is already opened, close it
581 //
582 if (Private->fd >= 0) {
583 BlockIo->Reset (BlockIo, FALSE);
584 }
585
586 //
587 // Open the device
588 //
589 Private->fd = Private->UnixThunk->Open (Private->Filename, Private->Mode, 0644);
590 if (Private->fd < 0) {
591 DEBUG ((EFI_D_INFO, "PlOpenBlock: Could not open %a\n", Private->Filename));
592 BlockIo->Media->MediaPresent = FALSE;
593 Status = EFI_NO_MEDIA;
594 goto Done;
595 }
596
597 if (!BlockIo->Media->MediaPresent) {
598 //
599 // BugBug: try to emulate if a CD appears - notify drivers to check it out
600 //
601 BlockIo->Media->MediaPresent = TRUE;
602 EfiReleaseLock (&Private->Lock);
603 EfiAcquireLock (&Private->Lock);
604 }
605
606 //
607 // get the size of the file
608 //
609 Status = SetFilePointer64 (Private, 0, &FileSize, SEEK_END);
610 if (EFI_ERROR (Status)) {
611 FileSize = MultU64x32 (Private->NumberOfBlocks, Private->BlockSize);
612 DEBUG ((EFI_D_ERROR, "PlOpenBlock: Could not get filesize of %a\n", Private->Filename));
613 Status = EFI_UNSUPPORTED;
614 goto Done;
615 }
616
617 if (Private->NumberOfBlocks == 0) {
618 Private->NumberOfBlocks = DivU64x32 (FileSize, Private->BlockSize);
619 Private->LastBlock = Private->NumberOfBlocks - 1;
620 Private->Media.LastBlock = Private->LastBlock;
621 }
622
623 EndOfFile = MultU64x32 (Private->NumberOfBlocks, Private->BlockSize);
624
625 if (FileSize != EndOfFile) {
626 //
627 // file is not the proper size, change it
628 //
629 DEBUG ((EFI_D_INIT, "PlOpenBlock: Initializing block device: %a\n", Private->Filename));
630
631 //
632 // first set it to 0
633 //
634 Private->UnixThunk->FTruncate (Private->fd, 0);
635
636 //
637 // then set it to the needed file size (OS will zero fill it)
638 //
639 Private->UnixThunk->FTruncate (Private->fd, EndOfFile);
640 }
641
642 DEBUG ((EFI_D_INIT, "%HPlOpenBlock: opened %a%N\n", Private->Filename));
643 Status = EFI_SUCCESS;
644
645 Done:
646 if (EFI_ERROR (Status)) {
647 if (Private->fd >= 0) {
648 BlockIo->Reset (BlockIo, FALSE);
649 }
650 }
651
652 EfiReleaseLock (&Private->Lock);
653 return Status;
654 }
655
656 EFI_STATUS
657 UnixBlockIoError (
658 IN EMU_BLOCK_IO_PRIVATE *Private
659 )
660 {
661 return EFI_DEVICE_ERROR;
662
663 #if 0
664 EFI_BLOCK_IO_PROTOCOL *BlockIo;
665 EFI_STATUS Status;
666 BOOLEAN ReinstallBlockIoFlag;
667
668
669 BlockIo = &Private->BlockIo;
670
671 switch (Private->UnixThunk->GetLastError ()) {
672
673 case ERROR_NOT_READY:
674 Status = EFI_NO_MEDIA;
675 BlockIo->Media->ReadOnly = FALSE;
676 BlockIo->Media->MediaPresent = FALSE;
677 ReinstallBlockIoFlag = FALSE;
678 break;
679
680 case ERROR_WRONG_DISK:
681 BlockIo->Media->ReadOnly = FALSE;
682 BlockIo->Media->MediaPresent = TRUE;
683 BlockIo->Media->MediaId += 1;
684 ReinstallBlockIoFlag = TRUE;
685 Status = EFI_MEDIA_CHANGED;
686 break;
687
688 case ERROR_WRITE_PROTECT:
689 BlockIo->Media->ReadOnly = TRUE;
690 ReinstallBlockIoFlag = FALSE;
691 Status = EFI_WRITE_PROTECTED;
692 break;
693
694 default:
695 ReinstallBlockIoFlag = FALSE;
696 Status = EFI_DEVICE_ERROR;
697 break;
698 }
699
700 if (ReinstallBlockIoFlag) {
701 BlockIo->Reset (BlockIo, FALSE);
702
703 gBS->ReinstallProtocolInterface (
704 Private->EfiHandle,
705 &gEfiBlockIoProtocolGuid,
706 BlockIo,
707 BlockIo
708 );
709 }
710
711 return Status;
712 #endif
713 }
714
715 EFI_STATUS
716 UnixBlockIoReadWriteCommon (
717 IN EMU_BLOCK_IO_PRIVATE *Private,
718 IN UINT32 MediaId,
719 IN EFI_LBA Lba,
720 IN UINTN BufferSize,
721 IN VOID *Buffer,
722 IN CHAR8 *CallerName
723 )
724 {
725 EFI_STATUS Status;
726 UINTN BlockSize;
727 UINT64 LastBlock;
728 INT64 DistanceToMove;
729 UINT64 DistanceMoved;
730
731 if (Private->fd < 0) {
732 Status = UnixBlockIoOpenDevice (Private);
733 if (EFI_ERROR (Status)) {
734 return Status;
735 }
736 }
737
738 if (!Private->Media.MediaPresent) {
739 DEBUG ((EFI_D_INIT, "%s: No Media\n", CallerName));
740 return EFI_NO_MEDIA;
741 }
742
743 if (Private->Media.MediaId != MediaId) {
744 return EFI_MEDIA_CHANGED;
745 }
746
747 if ((UINTN) Buffer % Private->Media.IoAlign != 0) {
748 return EFI_INVALID_PARAMETER;
749 }
750
751 //
752 // Verify buffer size
753 //
754 BlockSize = Private->BlockSize;
755 if (BufferSize == 0) {
756 DEBUG ((EFI_D_INIT, "%s: Zero length read\n", CallerName));
757 return EFI_SUCCESS;
758 }
759
760 if ((BufferSize % BlockSize) != 0) {
761 DEBUG ((EFI_D_INIT, "%s: Invalid read size\n", CallerName));
762 return EFI_BAD_BUFFER_SIZE;
763 }
764
765 LastBlock = Lba + (BufferSize / BlockSize) - 1;
766 if (LastBlock > Private->LastBlock) {
767 DEBUG ((EFI_D_INIT, "ReadBlocks: Attempted to read off end of device\n"));
768 return EFI_INVALID_PARAMETER;
769 }
770 //
771 // Seek to End of File
772 //
773 DistanceToMove = MultU64x32 (Lba, BlockSize);
774 Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, SEEK_SET);
775
776 if (EFI_ERROR (Status)) {
777 DEBUG ((EFI_D_INIT, "WriteBlocks: SetFilePointer failed\n"));
778 return UnixBlockIoError (Private);
779 }
780
781 return EFI_SUCCESS;
782 }
783
784 EFI_STATUS
785 EFIAPI
786 UnixBlockIoReadBlocks (
787 IN EFI_BLOCK_IO_PROTOCOL *This,
788 IN UINT32 MediaId,
789 IN EFI_LBA Lba,
790 IN UINTN BufferSize,
791 OUT VOID *Buffer
792 )
793 /*++
794
795 Routine Description:
796 Read BufferSize bytes from Lba into Buffer.
797
798 Arguments:
799 This - Protocol instance pointer.
800 MediaId - Id of the media, changes every time the media is replaced.
801 Lba - The starting Logical Block Address to read from
802 BufferSize - Size of Buffer, must be a multiple of device block size.
803 Buffer - Buffer containing read data
804
805 Returns:
806 EFI_SUCCESS - The data was read correctly from the device.
807 EFI_DEVICE_ERROR - The device reported an error while performing the read.
808 EFI_NO_MEDIA - There is no media in the device.
809 EFI_MEDIA_CHANGED - The MediaId does not matched the current device.
810 EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the
811 device.
812 EFI_INVALID_PARAMETER - The read request contains device addresses that are not
813 valid for the device.
814
815 **/
816 {
817 EMU_BLOCK_IO_PRIVATE *Private;
818 ssize_t len;
819 EFI_STATUS Status;
820 EFI_TPL OldTpl;
821
822 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
823
824 Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
825
826 Status = UnixBlockIoReadWriteCommon (Private, MediaId, Lba, BufferSize, Buffer, "UnixReadBlocks");
827 if (EFI_ERROR (Status)) {
828 goto Done;
829 }
830
831 len = Private->UnixThunk->Read (Private->fd, Buffer, BufferSize);
832 if (len != BufferSize) {
833 DEBUG ((EFI_D_INIT, "ReadBlocks: ReadFile failed.\n"));
834 Status = UnixBlockIoError (Private);
835 goto Done;
836 }
837
838 //
839 // If we wrote then media is present.
840 //
841 This->Media->MediaPresent = TRUE;
842 Status = EFI_SUCCESS;
843
844 Done:
845 gBS->RestoreTPL (OldTpl);
846 return Status;
847 }
848
849 EFI_STATUS
850 EFIAPI
851 UnixBlockIoWriteBlocks (
852 IN EFI_BLOCK_IO_PROTOCOL *This,
853 IN UINT32 MediaId,
854 IN EFI_LBA Lba,
855 IN UINTN BufferSize,
856 IN VOID *Buffer
857 )
858 /*++
859
860 Routine Description:
861 Write BufferSize bytes from Lba into Buffer.
862
863 Arguments:
864 This - Protocol instance pointer.
865 MediaId - Id of the media, changes every time the media is replaced.
866 Lba - The starting Logical Block Address to read from
867 BufferSize - Size of Buffer, must be a multiple of device block size.
868 Buffer - Buffer containing read data
869
870 Returns:
871 EFI_SUCCESS - The data was written correctly to the device.
872 EFI_WRITE_PROTECTED - The device can not be written to.
873 EFI_DEVICE_ERROR - The device reported an error while performing the write.
874 EFI_NO_MEDIA - There is no media in the device.
875 EFI_MEDIA_CHNAGED - The MediaId does not matched the current device.
876 EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the
877 device.
878 EFI_INVALID_PARAMETER - The write request contains a LBA that is not
879 valid for the device.
880
881 **/
882 {
883 EMU_BLOCK_IO_PRIVATE *Private;
884 ssize_t len;
885 EFI_STATUS Status;
886 EFI_TPL OldTpl;
887
888 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
889
890 Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
891
892 Status = UnixBlockIoReadWriteCommon (Private, MediaId, Lba, BufferSize, Buffer, "UnixWriteBlocks");
893 if (EFI_ERROR (Status)) {
894 goto Done;
895 }
896
897 len = Private->UnixThunk->Write (Private->fd, Buffer, BufferSize);
898 if (len != BufferSize) {
899 DEBUG ((EFI_D_INIT, "ReadBlocks: WriteFile failed.\n"));
900 Status = UnixBlockIoError (Private);
901 goto Done;
902 }
903
904 //
905 // If the write succeeded, we are not write protected and media is present.
906 //
907 This->Media->MediaPresent = TRUE;
908 This->Media->ReadOnly = FALSE;
909 Status = EFI_SUCCESS;
910
911 Done:
912 gBS->RestoreTPL (OldTpl);
913 return Status;
914 }
915
916 EFI_STATUS
917 EFIAPI
918 UnixBlockIoFlushBlocks (
919 IN EFI_BLOCK_IO_PROTOCOL *This
920 )
921 /*++
922
923 Routine Description:
924 Flush the Block Device.
925
926 Arguments:
927 This - Protocol instance pointer.
928
929 Returns:
930 EFI_SUCCESS - All outstanding data was written to the device
931 EFI_DEVICE_ERROR - The device reported an error while writting back the data
932 EFI_NO_MEDIA - There is no media in the device.
933
934 **/
935 {
936 return EFI_SUCCESS;
937 }
938
939 EFI_STATUS
940 EFIAPI
941 UnixBlockIoResetBlock (
942 IN EFI_BLOCK_IO_PROTOCOL *This,
943 IN BOOLEAN ExtendedVerification
944 )
945 /*++
946
947 Routine Description:
948 Reset the Block Device.
949
950 Arguments:
951 This - Protocol instance pointer.
952 ExtendedVerification - Driver may perform diagnostics on reset.
953
954 Returns:
955 EFI_SUCCESS - The device was reset.
956 EFI_DEVICE_ERROR - The device is not functioning properly and could
957 not be reset.
958
959 **/
960 {
961 EMU_BLOCK_IO_PRIVATE *Private;
962 EFI_TPL OldTpl;
963
964 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
965
966 Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
967
968 if (Private->fd >= 0) {
969 Private->UnixThunk->Close (Private->fd);
970 Private->fd = -1;
971 }
972
973 gBS->RestoreTPL (OldTpl);
974
975 return EFI_SUCCESS;
976 }
977
978 UINTN
979 Atoi (
980 CHAR16 *String
981 )
982 /*++
983
984 Routine Description:
985
986 Convert a unicode string to a UINTN
987
988 Arguments:
989
990 String - Unicode string.
991
992 Returns:
993
994 UINTN of the number represented by String.
995
996 **/
997 {
998 UINTN Number;
999 CHAR16 *Str;
1000
1001 //
1002 // skip preceeding white space
1003 //
1004 Str = String;
1005 while ((*Str) && (*Str == ' ')) {
1006 Str++;
1007 }
1008 //
1009 // Convert ot a Number
1010 //
1011 Number = 0;
1012 while (*Str != '\0') {
1013 if ((*Str >= '0') && (*Str <= '9')) {
1014 Number = (Number * 10) +*Str - '0';
1015 } else {
1016 break;
1017 }
1018
1019 Str++;
1020 }
1021
1022 return Number;
1023 }
1024
1025
1026 /*++
1027
1028 This function extends the capability of SetFilePointer to accept 64 bit parameters
1029
1030 **/
1031 EFI_STATUS
1032 SetFilePointer64 (
1033 IN EMU_BLOCK_IO_PRIVATE *Private,
1034 IN INT64 DistanceToMove,
1035 OUT UINT64 *NewFilePointer,
1036 IN INT32 MoveMethod
1037 )
1038 {
1039 EFI_STATUS Status;
1040 off_t res;
1041
1042 Status = EFI_SUCCESS;
1043 res = Private->UnixThunk->Lseek(Private->fd, DistanceToMove, MoveMethod);
1044 if (res == -1) {
1045 Status = EFI_INVALID_PARAMETER;
1046 }
1047
1048 if (NewFilePointer != NULL) {
1049 *NewFilePointer = res;
1050 }
1051
1052 return Status;
1053 }