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