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