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