]> git.proxmox.com Git - mirror_edk2.git/blame - UnixPkg/UnixBlockIoDxe/UnixBlockIo.c
Port EdkUnixPkg to UnixPkg. The changes are listed as follows:
[mirror_edk2.git] / UnixPkg / UnixBlockIoDxe / UnixBlockIo.c
CommitLineData
804405e7 1/*++\r
2\r
3Copyright (c) 2004 - 2007, 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 Posix APIs.\r
19 The configuration of what devices to mount or emulate comes from UNIX \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 UNIX 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 UNIX 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>\r
64#include <unistd.h>\r
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 0xa,\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) ) {\r
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 return Status;\r
390}\r
391\r
392EFI_STATUS\r
393EFIAPI\r
394UnixBlockIoDriverBindingStart (\r
395 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
396 IN EFI_HANDLE Handle,\r
397 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
398 )\r
399/*++\r
400\r
401Routine Description:\r
402\r
403Arguments:\r
404\r
405Returns:\r
406\r
407 None\r
408\r
409--*/\r
410// TODO: This - add argument and description to function comment\r
411// TODO: Handle - add argument and description to function comment\r
412// TODO: RemainingDevicePath - add argument and description to function comment\r
413{\r
414 EFI_STATUS Status;\r
415 EFI_UNIX_IO_PROTOCOL *UnixIo;\r
416 CHAR16 Buffer[FILENAME_BUFFER_SIZE];\r
417 CHAR16 *Str;\r
418 BOOLEAN RemovableMedia;\r
419 BOOLEAN WriteProtected;\r
420 UINTN NumberOfBlocks;\r
421 UINTN BlockSize;\r
422 INTN i;\r
423\r
424 //\r
425 // Grab the protocols we need\r
426 //\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 // Set DiskType\r
441 //\r
442 if (!CompareGuid (UnixIo->TypeGuid, &gEfiUnixVirtualDisksGuid)) {\r
443 Status = EFI_UNSUPPORTED;\r
444 goto Done;\r
445 }\r
446\r
447 Status = EFI_NOT_FOUND;\r
448 // Extract filename.\r
449 Str = UnixIo->EnvString;\r
450 i = 0;\r
451 while (*Str && *Str != ':')\r
452 Buffer[i++] = *Str++;\r
453 Buffer[i] = 0;\r
454 if (*Str != ':') {\r
455 goto Done;\r
456 }\r
457\r
458 Str++;\r
459\r
460 RemovableMedia = FALSE;\r
461 WriteProtected = TRUE;\r
462 NumberOfBlocks = 0;\r
463 BlockSize = 512;\r
464 do {\r
465 if (*Str == 'R' || *Str == 'F') {\r
466 RemovableMedia = (BOOLEAN) (*Str == 'R');\r
467 Str++;\r
468 }\r
469 if (*Str == 'O' || *Str == 'W') {\r
470 WriteProtected = (BOOLEAN) (*Str == 'O');\r
471 Str++;\r
472 }\r
473 if (*Str == 0)\r
474 break;\r
475 if (*Str != ';')\r
476 goto Done;\r
477 Str++;\r
478\r
479 NumberOfBlocks = Atoi (Str);\r
480 Str = GetNextElementPastTerminator (Str, ';');\r
481 if (NumberOfBlocks == 0)\r
482 break;\r
483\r
484 BlockSize = Atoi (Str);\r
485 if (BlockSize != 0)\r
486 Str = GetNextElementPastTerminator (Str, ';');\r
487 } while (0);\r
488\r
489 //\r
490 // If we get here the variable is valid so do the work.\r
491 //\r
492 Status = UnixBlockIoCreateMapping (\r
493 UnixIo,\r
494 Handle,\r
495 Buffer,\r
496 WriteProtected,\r
497 RemovableMedia,\r
498 NumberOfBlocks,\r
499 BlockSize\r
500 );\r
501\r
502Done:\r
503 if (EFI_ERROR (Status)) {\r
504 gBS->CloseProtocol (\r
505 Handle,\r
506 &gEfiUnixIoProtocolGuid,\r
507 This->DriverBindingHandle,\r
508 Handle\r
509 );\r
510 }\r
511\r
512 return Status;\r
513}\r
514\r
515EFI_STATUS\r
516EFIAPI\r
517UnixBlockIoDriverBindingStop (\r
518 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
519 IN EFI_HANDLE Handle,\r
520 IN UINTN NumberOfChildren,\r
521 IN EFI_HANDLE *ChildHandleBuffer\r
522 )\r
523/*++\r
524\r
525Routine Description:\r
526\r
527 TODO: Add function description\r
528\r
529Arguments:\r
530\r
531 This - TODO: add argument description\r
532 Handle - TODO: add argument description\r
533 NumberOfChildren - TODO: add argument description\r
534 ChildHandleBuffer - TODO: add argument description\r
535\r
536Returns:\r
537\r
538 EFI_UNSUPPORTED - TODO: Add description for return value\r
539\r
540--*/\r
541{\r
542 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
543 EFI_STATUS Status;\r
544 UNIX_BLOCK_IO_PRIVATE *Private;\r
545\r
546 //\r
547 // Get our context back\r
548 //\r
549 Status = gBS->OpenProtocol (\r
550 Handle,\r
551 &gEfiBlockIoProtocolGuid,\r
552 (void *)&BlockIo,\r
553 This->DriverBindingHandle,\r
554 Handle,\r
555 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
556 );\r
557 if (EFI_ERROR (Status)) {\r
558 return EFI_UNSUPPORTED;\r
559 }\r
560\r
561 Private = UNIX_BLOCK_IO_PRIVATE_DATA_FROM_THIS (BlockIo);\r
562\r
563 //\r
564 // BugBug: If we need to kick people off, we need to make Uninstall Close the handles.\r
565 // We could pass in our image handle or FLAG our open to be closed via\r
566 // Unistall (== to saying any CloseProtocol will close our open)\r
567 //\r
568 Status = gBS->UninstallMultipleProtocolInterfaces (\r
569 Private->EfiHandle,\r
570 &gEfiBlockIoProtocolGuid,\r
571 &Private->BlockIo,\r
572 NULL\r
573 );\r
574 if (!EFI_ERROR (Status)) {\r
575\r
576 Status = gBS->CloseProtocol (\r
577 Handle,\r
578 &gEfiUnixIoProtocolGuid,\r
579 This->DriverBindingHandle,\r
580 Handle\r
581 );\r
582\r
583 //\r
584 // Shut down our device\r
585 //\r
586 Private->UnixThunk->Close (Private->fd);\r
587\r
588 //\r
589 // Free our instance data\r
590 //\r
591 FreeUnicodeStringTable (Private->ControllerNameTable);\r
592\r
593 gBS->FreePool (Private);\r
594 }\r
595\r
596 return Status;\r
597}\r
598\r
599STATIC\r
600CHAR16 *\r
601GetNextElementPastTerminator (\r
602 IN CHAR16 *EnvironmentVariable,\r
603 IN CHAR16 Terminator\r
604 )\r
605/*++\r
606\r
607Routine Description:\r
608\r
609 Worker function to parse environment variables.\r
610\r
611Arguments:\r
612 EnvironmentVariable - Envirnment variable to parse.\r
613\r
614 Terminator - Terminator to parse for.\r
615\r
616Returns: \r
617\r
618 Pointer to next eliment past the first occurence of Terminator or the '\0'\r
619 at the end of the string.\r
620\r
621--*/\r
622{\r
623 CHAR16 *Ptr;\r
624\r
625 for (Ptr = EnvironmentVariable; *Ptr != '\0'; Ptr++) {\r
626 if (*Ptr == Terminator) {\r
627 Ptr++;\r
628 break;\r
629 }\r
630 }\r
631\r
632 return Ptr;\r
633}\r
634\r
635STATIC\r
636EFI_STATUS\r
637UnixBlockIoCreateMapping (\r
638 IN EFI_UNIX_IO_PROTOCOL *UnixIo,\r
639 IN EFI_HANDLE EfiDeviceHandle,\r
640 IN CHAR16 *Filename,\r
641 IN BOOLEAN ReadOnly,\r
642 IN BOOLEAN RemovableMedia,\r
643 IN UINTN NumberOfBlocks,\r
644 IN UINTN BlockSize\r
645 )\r
646/*++\r
647\r
648Routine Description:\r
649\r
650 TODO: Add function description\r
651\r
652Arguments:\r
653\r
654 UnixIo - TODO: add argument description\r
655 EfiDeviceHandle - TODO: add argument description\r
656 Filename - TODO: add argument description\r
657 ReadOnly - TODO: add argument description\r
658 RemovableMedia - TODO: add argument description\r
659 NumberOfBlocks - TODO: add argument description\r
660 BlockSize - TODO: add argument description\r
661 DeviceType - TODO: add argument description\r
662\r
663Returns:\r
664\r
665 TODO: add return values\r
666\r
667--*/\r
668{\r
669 EFI_STATUS Status;\r
670 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
671 UNIX_BLOCK_IO_PRIVATE *Private;\r
672 UINTN Index;\r
673\r
674 Status = gBS->AllocatePool (\r
675 EfiBootServicesData,\r
676 sizeof (UNIX_BLOCK_IO_PRIVATE),\r
677 (void *)&Private\r
678 );\r
679 ASSERT_EFI_ERROR (Status);\r
680\r
681 EfiInitializeLock (&Private->Lock, TPL_NOTIFY);\r
682\r
683 Private->UnixThunk = UnixIo->UnixThunk;\r
684\r
685 Private->Signature = UNIX_BLOCK_IO_PRIVATE_SIGNATURE;\r
686 Private->LastBlock = NumberOfBlocks - 1;\r
687 Private->BlockSize = BlockSize;\r
688\r
689 for (Index = 0; Filename[Index] != 0; Index++) {\r
690 Private->Filename[Index] = Filename[Index];\r
691 }\r
692\r
693 Private->Filename[Index] = 0;\r
694\r
695 Private->Mode = (ReadOnly ? O_RDONLY : O_RDWR);\r
696\r
697 Private->NumberOfBlocks = NumberOfBlocks;\r
698 Private->fd = -1;\r
699\r
700 Private->ControllerNameTable = NULL;\r
701\r
702 AddUnicodeString (\r
703 "eng",\r
704 gUnixBlockIoComponentName.SupportedLanguages,\r
705 &Private->ControllerNameTable,\r
706 Filename\r
707 );\r
708\r
709 BlockIo = &Private->BlockIo;\r
710 BlockIo->Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;\r
711 BlockIo->Media = &Private->Media;\r
712 BlockIo->Media->BlockSize = Private->BlockSize;\r
713 BlockIo->Media->LastBlock = Private->NumberOfBlocks - 1;\r
714 BlockIo->Media->MediaId = 0;;\r
715\r
716 BlockIo->Reset = UnixBlockIoResetBlock;\r
717 BlockIo->ReadBlocks = UnixBlockIoReadBlocks;\r
718 BlockIo->WriteBlocks = UnixBlockIoWriteBlocks;\r
719 BlockIo->FlushBlocks = UnixBlockIoFlushBlocks;\r
720\r
721 BlockIo->Media->ReadOnly = ReadOnly;\r
722 BlockIo->Media->RemovableMedia = RemovableMedia;\r
723 BlockIo->Media->LogicalPartition = FALSE;\r
724 BlockIo->Media->MediaPresent = TRUE;\r
725 BlockIo->Media->WriteCaching = FALSE;\r
726\r
727 BlockIo->Media->IoAlign = 1;\r
728\r
729 Private->EfiHandle = EfiDeviceHandle;\r
730 Status = UnixBlockIoOpenDevice (Private);\r
731 if (!EFI_ERROR (Status)) {\r
732\r
733 Status = gBS->InstallMultipleProtocolInterfaces (\r
734 &Private->EfiHandle,\r
735 &gEfiBlockIoProtocolGuid,\r
736 &Private->BlockIo,\r
737 NULL\r
738 );\r
739 if (EFI_ERROR (Status)) {\r
740 FreeUnicodeStringTable (Private->ControllerNameTable);\r
741 gBS->FreePool (Private);\r
742 }\r
743\r
744 DEBUG ((EFI_D_ERROR, "BlockDevice added: %s\n", Filename));\r
745 }\r
746\r
747 return Status;\r
748}\r
749\r
750STATIC\r
751EFI_STATUS\r
752UnixBlockIoOpenDevice (\r
753 UNIX_BLOCK_IO_PRIVATE *Private\r
754 )\r
755/*++\r
756\r
757Routine Description:\r
758\r
759 TODO: Add function description\r
760\r
761Arguments:\r
762\r
763 Private - TODO: add argument description\r
764\r
765Returns:\r
766\r
767 TODO: add return values\r
768\r
769--*/\r
770{\r
771 EFI_STATUS Status;\r
772 UINT64 FileSize;\r
773 UINT64 EndOfFile;\r
774 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
775\r
776 BlockIo = &Private->BlockIo;\r
777 EfiAcquireLock (&Private->Lock);\r
778\r
779 //\r
780 // If the device is already opened, close it\r
781 //\r
782 if (Private->fd >= 0) {\r
783 BlockIo->Reset (BlockIo, FALSE);\r
784 }\r
785\r
786 //\r
787 // Open the device\r
788 //\r
789 Private->fd = Private->UnixThunk->Open\r
790 (Private->Filename, Private->Mode, 0644);\r
791\r
792 if (Private->fd < 0) {\r
793 DEBUG ((EFI_D_INFO, "PlOpenBlock: Could not open %s\n",\r
794 Private->Filename));\r
795 BlockIo->Media->MediaPresent = FALSE;\r
796 Status = EFI_NO_MEDIA;\r
797 goto Done;\r
798 }\r
799\r
800 if (!BlockIo->Media->MediaPresent) {\r
801 //\r
802 // BugBug: try to emulate if a CD appears - notify drivers to check it out\r
803 //\r
804 BlockIo->Media->MediaPresent = TRUE;\r
805 EfiReleaseLock (&Private->Lock);\r
806 EfiAcquireLock (&Private->Lock);\r
807 }\r
808\r
809 //\r
810 // get the size of the file\r
811 //\r
812 Status = SetFilePointer64 (Private, 0, &FileSize, SEEK_END);\r
813\r
814 if (EFI_ERROR (Status)) {\r
815 FileSize = MultU64x32 (Private->NumberOfBlocks, Private->BlockSize);\r
816 DEBUG ((EFI_D_ERROR, "PlOpenBlock: Could not get filesize of %s\n", Private->Filename));\r
817 Status = EFI_UNSUPPORTED;\r
818 goto Done;\r
819 }\r
820\r
821 if (Private->NumberOfBlocks == 0) {\r
822 Private->NumberOfBlocks = DivU64x32 (FileSize, Private->BlockSize);\r
823 }\r
824\r
825 EndOfFile = MultU64x32 (Private->NumberOfBlocks, Private->BlockSize);\r
826\r
827 if (FileSize != EndOfFile) {\r
828 //\r
829 // file is not the proper size, change it\r
830 //\r
831 DEBUG ((EFI_D_INIT, "PlOpenBlock: Initializing block device: %a\n", Private->Filename));\r
832\r
833 //\r
834 // first set it to 0\r
835 //\r
836 Private->UnixThunk->FTruncate (Private->fd, 0);\r
837\r
838 //\r
839 // then set it to the needed file size (OS will zero fill it)\r
840 //\r
841 Private->UnixThunk->FTruncate (Private->fd, EndOfFile);\r
842 }\r
843\r
844 DEBUG ((EFI_D_INIT, "%HPlOpenBlock: opened %s%N\n", Private->Filename));\r
845 Status = EFI_SUCCESS;\r
846\r
847Done:\r
848 if (EFI_ERROR (Status)) {\r
849 if (Private->fd >= 0) {\r
850 BlockIo->Reset (BlockIo, FALSE);\r
851 }\r
852 }\r
853\r
854 EfiReleaseLock (&Private->Lock);\r
855 return Status;\r
856}\r
857\r
858STATIC\r
859EFI_STATUS\r
860UnixBlockIoError (\r
861 IN UNIX_BLOCK_IO_PRIVATE *Private\r
862 )\r
863/*++\r
864\r
865Routine Description:\r
866\r
867 TODO: Add function description\r
868\r
869Arguments:\r
870\r
871 Private - TODO: add argument description\r
872\r
873Returns:\r
874\r
875 TODO: add return values\r
876\r
877--*/\r
878{\r
879 return EFI_DEVICE_ERROR;\r
880\r
881#if 0\r
882 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
883 EFI_STATUS Status;\r
884 BOOLEAN ReinstallBlockIoFlag;\r
885\r
886\r
887 BlockIo = &Private->BlockIo;\r
888\r
889 switch (Private->UnixThunk->GetLastError ()) {\r
890\r
891 case ERROR_NOT_READY:\r
892 Status = EFI_NO_MEDIA;\r
893 BlockIo->Media->ReadOnly = FALSE;\r
894 BlockIo->Media->MediaPresent = FALSE;\r
895 ReinstallBlockIoFlag = FALSE;\r
896 break;\r
897\r
898 case ERROR_WRONG_DISK:\r
899 BlockIo->Media->ReadOnly = FALSE;\r
900 BlockIo->Media->MediaPresent = TRUE;\r
901 BlockIo->Media->MediaId += 1;\r
902 ReinstallBlockIoFlag = TRUE;\r
903 Status = EFI_MEDIA_CHANGED;\r
904 break;\r
905\r
906 case ERROR_WRITE_PROTECT:\r
907 BlockIo->Media->ReadOnly = TRUE;\r
908 ReinstallBlockIoFlag = FALSE;\r
909 Status = EFI_WRITE_PROTECTED;\r
910 break;\r
911\r
912 default:\r
913 ReinstallBlockIoFlag = FALSE;\r
914 Status = EFI_DEVICE_ERROR;\r
915 break;\r
916 }\r
917\r
918 if (ReinstallBlockIoFlag) {\r
919 BlockIo->Reset (BlockIo, FALSE);\r
920\r
921 gBS->ReinstallProtocolInterface (\r
922 Private->EfiHandle,\r
923 &gEfiBlockIoProtocolGuid,\r
924 BlockIo,\r
925 BlockIo\r
926 );\r
927 }\r
928\r
929 return Status;\r
930#endif\r
931}\r
932\r
933STATIC\r
934EFI_STATUS\r
935UnixBlockIoReadWriteCommon (\r
936 IN UNIX_BLOCK_IO_PRIVATE *Private,\r
937 IN UINT32 MediaId,\r
938 IN EFI_LBA Lba,\r
939 IN UINTN BufferSize,\r
940 IN VOID *Buffer,\r
941 IN CHAR8 *CallerName\r
942 )\r
943/*++\r
944\r
945Routine Description:\r
946\r
947 TODO: Add function description\r
948\r
949Arguments:\r
950\r
951 Private - TODO: add argument description\r
952 MediaId - TODO: add argument description\r
953 Lba - TODO: add argument description\r
954 BufferSize - TODO: add argument description\r
955 Buffer - TODO: add argument description\r
956 CallerName - TODO: add argument description\r
957\r
958Returns:\r
959\r
960 EFI_NO_MEDIA - TODO: Add description for return value\r
961 EFI_MEDIA_CHANGED - TODO: Add description for return value\r
962 EFI_INVALID_PARAMETER - TODO: Add description for return value\r
963 EFI_SUCCESS - TODO: Add description for return value\r
964 EFI_BAD_BUFFER_SIZE - TODO: Add description for return value\r
965 EFI_INVALID_PARAMETER - TODO: Add description for return value\r
966 EFI_SUCCESS - TODO: Add description for return value\r
967\r
968--*/\r
969{\r
970 EFI_STATUS Status;\r
971 UINTN BlockSize;\r
972 UINT64 LastBlock;\r
973 INT64 DistanceToMove;\r
974 UINT64 DistanceMoved;\r
975\r
976 if (Private->fd < 0) {\r
977 Status = UnixBlockIoOpenDevice (Private);\r
978 if (EFI_ERROR (Status)) {\r
979 return Status;\r
980 }\r
981 }\r
982\r
983 if (!Private->Media.MediaPresent) {\r
984 DEBUG ((EFI_D_INIT, "%s: No Media\n", CallerName));\r
985 return EFI_NO_MEDIA;\r
986 }\r
987\r
988 if (Private->Media.MediaId != MediaId) {\r
989 return EFI_MEDIA_CHANGED;\r
990 }\r
991\r
992 if ((UINT32) Buffer % Private->Media.IoAlign != 0) {\r
993 return EFI_INVALID_PARAMETER;\r
994 }\r
995 \r
996 //\r
997 // Verify buffer size\r
998 //\r
999 BlockSize = Private->BlockSize;\r
1000 if (BufferSize == 0) {\r
1001 DEBUG ((EFI_D_INIT, "%s: Zero length read\n", CallerName));\r
1002 return EFI_SUCCESS;\r
1003 }\r
1004\r
1005 if ((BufferSize % BlockSize) != 0) {\r
1006 DEBUG ((EFI_D_INIT, "%s: Invalid read size\n", CallerName));\r
1007 return EFI_BAD_BUFFER_SIZE;\r
1008 }\r
1009\r
1010 LastBlock = Lba + (BufferSize / BlockSize) - 1;\r
1011 if (LastBlock > Private->LastBlock) {\r
1012 DEBUG ((EFI_D_INIT, "ReadBlocks: Attempted to read off end of device\n"));\r
1013 return EFI_INVALID_PARAMETER;\r
1014 }\r
1015 //\r
1016 // Seek to End of File\r
1017 //\r
1018 DistanceToMove = MultU64x32 (Lba, BlockSize);\r
1019 Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, SEEK_SET);\r
1020\r
1021 if (EFI_ERROR (Status)) {\r
1022 DEBUG ((EFI_D_INIT, "WriteBlocks: SetFilePointer failed\n"));\r
1023 return UnixBlockIoError (Private);\r
1024 }\r
1025\r
1026 return EFI_SUCCESS;\r
1027}\r
1028\r
1029STATIC\r
1030EFI_STATUS\r
1031EFIAPI\r
1032UnixBlockIoReadBlocks (\r
1033 IN EFI_BLOCK_IO_PROTOCOL *This,\r
1034 IN UINT32 MediaId,\r
1035 IN EFI_LBA Lba,\r
1036 IN UINTN BufferSize,\r
1037 OUT VOID *Buffer\r
1038 )\r
1039/*++\r
1040\r
1041 Routine Description:\r
1042 Read BufferSize bytes from Lba into Buffer.\r
1043\r
1044 Arguments:\r
1045 This - Protocol instance pointer.\r
1046 MediaId - Id of the media, changes every time the media is replaced.\r
1047 Lba - The starting Logical Block Address to read from\r
1048 BufferSize - Size of Buffer, must be a multiple of device block size.\r
1049 Buffer - Buffer containing read data\r
1050\r
1051 Returns:\r
1052 EFI_SUCCESS - The data was read correctly from the device.\r
1053 EFI_DEVICE_ERROR - The device reported an error while performing the read.\r
1054 EFI_NO_MEDIA - There is no media in the device.\r
1055 EFI_MEDIA_CHANGED - The MediaId does not matched the current device.\r
1056 EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the \r
1057 device.\r
1058 EFI_INVALID_PARAMETER - The read request contains device addresses that are not \r
1059 valid for the device.\r
1060\r
1061--*/\r
1062{\r
1063 UNIX_BLOCK_IO_PRIVATE *Private;\r
1064 ssize_t len;\r
1065 EFI_STATUS Status;\r
1066 EFI_TPL OldTpl;\r
1067\r
1068 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
1069\r
1070 Private = UNIX_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r
1071\r
1072 Status = UnixBlockIoReadWriteCommon (Private, MediaId, Lba, BufferSize, Buffer, "UnixReadBlocks");\r
1073 if (EFI_ERROR (Status)) {\r
1074 goto Done;\r
1075 }\r
1076\r
1077 len = Private->UnixThunk->Read (Private->fd, Buffer, BufferSize);\r
1078 if (len != BufferSize) {\r
1079 DEBUG ((EFI_D_INIT, "ReadBlocks: ReadFile failed.\n"));\r
1080 Status = UnixBlockIoError (Private);\r
1081 goto Done;\r
1082 }\r
1083\r
1084 //\r
1085 // If we wrote then media is present.\r
1086 //\r
1087 This->Media->MediaPresent = TRUE;\r
1088 Status = EFI_SUCCESS;\r
1089\r
1090Done:\r
1091 gBS->RestoreTPL (OldTpl);\r
1092 return Status;\r
1093}\r
1094\r
1095STATIC\r
1096EFI_STATUS\r
1097EFIAPI\r
1098UnixBlockIoWriteBlocks (\r
1099 IN EFI_BLOCK_IO_PROTOCOL *This,\r
1100 IN UINT32 MediaId,\r
1101 IN EFI_LBA Lba,\r
1102 IN UINTN BufferSize,\r
1103 IN VOID *Buffer\r
1104 )\r
1105/*++\r
1106\r
1107 Routine Description:\r
1108 Write BufferSize bytes from Lba into Buffer.\r
1109\r
1110 Arguments:\r
1111 This - Protocol instance pointer.\r
1112 MediaId - Id of the media, changes every time the media is replaced.\r
1113 Lba - The starting Logical Block Address to read from\r
1114 BufferSize - Size of Buffer, must be a multiple of device block size.\r
1115 Buffer - Buffer containing read data\r
1116\r
1117 Returns:\r
1118 EFI_SUCCESS - The data was written correctly to the device.\r
1119 EFI_WRITE_PROTECTED - The device can not be written to.\r
1120 EFI_DEVICE_ERROR - The device reported an error while performing the write.\r
1121 EFI_NO_MEDIA - There is no media in the device.\r
1122 EFI_MEDIA_CHNAGED - The MediaId does not matched the current device.\r
1123 EFI_BAD_BUFFER_SIZE - The Buffer was not a multiple of the block size of the \r
1124 device.\r
1125 EFI_INVALID_PARAMETER - The write request contains a LBA that is not \r
1126 valid for the device.\r
1127\r
1128--*/\r
1129{\r
1130 UNIX_BLOCK_IO_PRIVATE *Private;\r
1131 ssize_t len;\r
1132 EFI_STATUS Status;\r
1133 EFI_TPL OldTpl;\r
1134\r
1135 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
1136\r
1137 Private = UNIX_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r
1138\r
1139 Status = UnixBlockIoReadWriteCommon (Private, MediaId, Lba, BufferSize, Buffer, "UnixWriteBlocks");\r
1140 if (EFI_ERROR (Status)) {\r
1141 goto Done;\r
1142 }\r
1143\r
1144 len = Private->UnixThunk->Write (Private->fd, Buffer, BufferSize);\r
1145 if (len != BufferSize) {\r
1146 DEBUG ((EFI_D_INIT, "ReadBlocks: WriteFile failed.\n"));\r
1147 Status = UnixBlockIoError (Private);\r
1148 goto Done;\r
1149 }\r
1150\r
1151 //\r
1152 // If the write succeeded, we are not write protected and media is present.\r
1153 //\r
1154 This->Media->MediaPresent = TRUE;\r
1155 This->Media->ReadOnly = FALSE;\r
1156 Status = EFI_SUCCESS;\r
1157\r
1158Done:\r
1159 gBS->RestoreTPL (OldTpl);\r
1160 return Status;\r
1161}\r
1162\r
1163STATIC\r
1164EFI_STATUS\r
1165EFIAPI\r
1166UnixBlockIoFlushBlocks (\r
1167 IN EFI_BLOCK_IO_PROTOCOL *This\r
1168 )\r
1169/*++\r
1170\r
1171 Routine Description:\r
1172 Flush the Block Device.\r
1173\r
1174 Arguments:\r
1175 This - Protocol instance pointer.\r
1176\r
1177 Returns:\r
1178 EFI_SUCCESS - All outstanding data was written to the device\r
1179 EFI_DEVICE_ERROR - The device reported an error while writting back the data\r
1180 EFI_NO_MEDIA - There is no media in the device.\r
1181\r
1182--*/\r
1183{\r
1184 return EFI_SUCCESS;\r
1185}\r
1186\r
1187STATIC\r
1188EFI_STATUS\r
1189EFIAPI\r
1190UnixBlockIoResetBlock (\r
1191 IN EFI_BLOCK_IO_PROTOCOL *This,\r
1192 IN BOOLEAN ExtendedVerification\r
1193 )\r
1194/*++\r
1195\r
1196 Routine Description:\r
1197 Reset the Block Device.\r
1198\r
1199 Arguments:\r
1200 This - Protocol instance pointer.\r
1201 ExtendedVerification - Driver may perform diagnostics on reset.\r
1202\r
1203 Returns:\r
1204 EFI_SUCCESS - The device was reset.\r
1205 EFI_DEVICE_ERROR - The device is not functioning properly and could \r
1206 not be reset.\r
1207\r
1208--*/\r
1209{\r
1210 UNIX_BLOCK_IO_PRIVATE *Private;\r
1211 EFI_TPL OldTpl;\r
1212\r
1213 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
1214 \r
1215 Private = UNIX_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r
1216\r
1217 if (Private->fd >= 0) {\r
1218 Private->UnixThunk->Close (Private->fd);\r
1219 Private->fd = -1;\r
1220 }\r
1221\r
1222 gBS->RestoreTPL (OldTpl);\r
1223\r
1224 return EFI_SUCCESS;\r
1225}\r
1226\r
1227UINTN\r
1228Atoi (\r
1229 CHAR16 *String\r
1230 )\r
1231/*++\r
1232\r
1233Routine Description:\r
1234\r
1235 Convert a unicode string to a UINTN\r
1236\r
1237Arguments:\r
1238\r
1239 String - Unicode string.\r
1240\r
1241Returns: \r
1242\r
1243 UINTN of the number represented by String. \r
1244\r
1245--*/\r
1246{\r
1247 UINTN Number;\r
1248 CHAR16 *Str;\r
1249\r
1250 //\r
1251 // skip preceeding white space\r
1252 //\r
1253 Str = String;\r
1254 while ((*Str) && (*Str == ' ')) {\r
1255 Str++;\r
1256 }\r
1257 //\r
1258 // Convert ot a Number\r
1259 //\r
1260 Number = 0;\r
1261 while (*Str != '\0') {\r
1262 if ((*Str >= '0') && (*Str <= '9')) {\r
1263 Number = (Number * 10) +*Str - '0';\r
1264 } else {\r
1265 break;\r
1266 }\r
1267\r
1268 Str++;\r
1269 }\r
1270\r
1271 return Number;\r
1272}\r
1273\r
1274EFI_STATUS\r
1275SetFilePointer64 (\r
1276 IN UNIX_BLOCK_IO_PRIVATE *Private,\r
1277 IN INT64 DistanceToMove,\r
1278 OUT UINT64 *NewFilePointer,\r
1279 IN INTN MoveMethod\r
1280 )\r
1281/*++\r
1282\r
1283This function extends the capability of SetFilePointer to accept 64 bit parameters\r
1284\r
1285--*/\r
1286// TODO: function comment is missing 'Routine Description:'\r
1287// TODO: function comment is missing 'Arguments:'\r
1288// TODO: function comment is missing 'Returns:'\r
1289// TODO: Private - add argument and description to function comment\r
1290// TODO: DistanceToMove - add argument and description to function comment\r
1291// TODO: NewFilePointer - add argument and description to function comment\r
1292// TODO: MoveMethod - add argument and description to function comment\r
1293{\r
1294 EFI_STATUS Status;\r
1295 off_t res;\r
1296\r
1297 res = Private->UnixThunk->Lseek(Private->fd, DistanceToMove, MoveMethod);\r
1298 if (res == -1) {\r
1299 Status = EFI_INVALID_PARAMETER;\r
1300 }\r
1301\r
1302 if (NewFilePointer != NULL) {\r
1303 *NewFilePointer = res;\r
1304 }\r
1305\r
1306 return Status;\r
1307}\r