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