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