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