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