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