]> git.proxmox.com Git - mirror_edk2.git/blame - EmulatorPkg/Win/Host/WinBlockIo.c
EmulatorPkg: Apply uncrustify changes
[mirror_edk2.git] / EmulatorPkg / Win / Host / WinBlockIo.c
CommitLineData
8f819697
RN
1/**@file\r
2\r
3Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
e3ba31da 4SPDX-License-Identifier: BSD-2-Clause-Patent\r
8f819697
RN
5\r
6**/\r
7\r
8#include "WinHost.h"\r
9\r
a550d468 10#define WIN_NT_BLOCK_IO_PRIVATE_SIGNATURE SIGNATURE_32 ('N', 'T', 'b', 'k')\r
8f819697 11typedef struct {\r
a550d468 12 UINTN Signature;\r
8f819697 13\r
a550d468 14 EMU_IO_THUNK_PROTOCOL *Thunk;\r
8f819697 15\r
a550d468
MK
16 CHAR16 *FileName;\r
17 BOOLEAN Removable;\r
18 BOOLEAN Readonly;\r
8f819697 19\r
a550d468
MK
20 HANDLE NtHandle;\r
21 UINT32 BlockSize;\r
8f819697 22\r
a550d468
MK
23 EFI_BLOCK_IO_MEDIA *Media;\r
24 EMU_BLOCK_IO_PROTOCOL EmuBlockIo;\r
8f819697
RN
25} WIN_NT_BLOCK_IO_PRIVATE;\r
26\r
27#define WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS(a) \\r
28 CR(a, WIN_NT_BLOCK_IO_PRIVATE, EmuBlockIo, WIN_NT_BLOCK_IO_PRIVATE_SIGNATURE)\r
29\r
8f819697
RN
30EFI_STATUS\r
31WinNtBlockIoReset (\r
a550d468
MK
32 IN EMU_BLOCK_IO_PROTOCOL *This,\r
33 IN BOOLEAN ExtendedVerification\r
8f819697
RN
34 );\r
35\r
8f819697
RN
36EFI_STATUS\r
37SetFilePointer64 (\r
a550d468
MK
38 IN WIN_NT_BLOCK_IO_PRIVATE *Private,\r
39 IN INT64 DistanceToMove,\r
40 OUT UINT64 *NewFilePointer,\r
41 IN DWORD MoveMethod\r
42 )\r
43\r
8f819697
RN
44/*++\r
45\r
46This function extends the capability of SetFilePointer to accept 64 bit parameters\r
47\r
48--*/\r
49{\r
a550d468
MK
50 EFI_STATUS Status;\r
51 LARGE_INTEGER LargeInt;\r
8f819697
RN
52\r
53 LargeInt.QuadPart = DistanceToMove;\r
a550d468 54 Status = EFI_SUCCESS;\r
8f819697
RN
55\r
56 LargeInt.LowPart = SetFilePointer (\r
a550d468
MK
57 Private->NtHandle,\r
58 LargeInt.LowPart,\r
59 &LargeInt.HighPart,\r
60 MoveMethod\r
61 );\r
8f819697 62\r
a550d468 63 if ((LargeInt.LowPart == -1) && (GetLastError () != NO_ERROR)) {\r
8f819697
RN
64 Status = EFI_INVALID_PARAMETER;\r
65 }\r
66\r
67 if (NewFilePointer != NULL) {\r
68 *NewFilePointer = LargeInt.QuadPart;\r
69 }\r
70\r
71 return Status;\r
72}\r
73\r
8f819697
RN
74EFI_STATUS\r
75WinNtBlockIoOpenDevice (\r
a550d468
MK
76 IN WIN_NT_BLOCK_IO_PRIVATE *Private,\r
77 IN EFI_BLOCK_IO_MEDIA *Media\r
8f819697
RN
78 )\r
79{\r
a550d468
MK
80 EFI_STATUS Status;\r
81 UINT64 FileSize;\r
8f819697
RN
82\r
83 //\r
84 // If the device is already opened, close it\r
85 //\r
86 if (Private->NtHandle != INVALID_HANDLE_VALUE) {\r
87 WinNtBlockIoReset (&Private->EmuBlockIo, FALSE);\r
88 }\r
89\r
90 //\r
91 // Open the device\r
92 //\r
93 Private->NtHandle = CreateFile (\r
a550d468
MK
94 Private->FileName,\r
95 GENERIC_READ | (Private->Readonly ? 0 : GENERIC_WRITE),\r
96 FILE_SHARE_READ | FILE_SHARE_WRITE,\r
97 NULL,\r
98 OPEN_ALWAYS, // Create if it doesn't exist\r
99 0,\r
100 NULL\r
101 );\r
8f819697
RN
102\r
103 if (Private->NtHandle == INVALID_HANDLE_VALUE) {\r
9c7da8d8 104 DEBUG ((DEBUG_INFO, "OpenBlock: Could not open %S, %x\n", Private->FileName, GetLastError ()));\r
8f819697 105 Media->MediaPresent = FALSE;\r
a550d468 106 Status = EFI_NO_MEDIA;\r
8f819697
RN
107 goto Done;\r
108 }\r
109\r
110 //\r
111 // get the size of the file\r
112 //\r
113 Status = SetFilePointer64 (Private, 0, &FileSize, FILE_END);\r
114\r
115 if (EFI_ERROR (Status)) {\r
9c7da8d8 116 DEBUG ((DEBUG_ERROR, "OpenBlock: Could not get filesize of %s\n", Private->FileName));\r
8f819697
RN
117 Status = EFI_UNSUPPORTED;\r
118 goto Done;\r
119 }\r
120\r
121 Media->LastBlock = DivU64x32 (FileSize, (UINT32)Private->BlockSize) - 1;\r
122\r
9c7da8d8 123 DEBUG ((DEBUG_INIT, "OpenBlock: opened %S\n", Private->FileName));\r
8f819697
RN
124 Status = EFI_SUCCESS;\r
125\r
126Done:\r
127 if (EFI_ERROR (Status)) {\r
128 if (Private->NtHandle != INVALID_HANDLE_VALUE) {\r
129 WinNtBlockIoReset (&Private->EmuBlockIo, FALSE);\r
130 }\r
131 }\r
132\r
133 return Status;\r
134}\r
135\r
8f819697
RN
136EFI_STATUS\r
137EFIAPI\r
138WinNtBlockIoCreateMapping (\r
a550d468
MK
139 IN EMU_BLOCK_IO_PROTOCOL *This,\r
140 IN EFI_BLOCK_IO_MEDIA *Media\r
8f819697
RN
141 )\r
142{\r
a550d468 143 WIN_NT_BLOCK_IO_PRIVATE *Private;\r
8f819697
RN
144\r
145 Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r
146\r
147 Media->MediaId = 0;\r
148 Media->RemovableMedia = Private->Removable;\r
149 Media->MediaPresent = TRUE;\r
150 Media->LogicalPartition = FALSE;\r
151 Media->ReadOnly = Private->Readonly;\r
152 Media->WriteCaching = FALSE;\r
153 Media->IoAlign = 1;\r
154 Media->LastBlock = 0; // Filled in by OpenDevice\r
155 Media->BlockSize = Private->BlockSize;\r
156\r
157 // EFI_BLOCK_IO_PROTOCOL_REVISION2\r
158 Media->LowestAlignedLba = 0;\r
159 Media->LogicalBlocksPerPhysicalBlock = 0;\r
160\r
8f819697
RN
161 // EFI_BLOCK_IO_PROTOCOL_REVISION3\r
162 Media->OptimalTransferLengthGranularity = 0;\r
163\r
164 //\r
165 // Remember the Media pointer.\r
166 //\r
167 Private->Media = Media;\r
168 return WinNtBlockIoOpenDevice (Private, Media);\r
169}\r
170\r
8f819697
RN
171EFI_STATUS\r
172WinNtBlockIoError (\r
a550d468
MK
173 IN WIN_NT_BLOCK_IO_PRIVATE *Private\r
174 )\r
175\r
8f819697
RN
176/*++\r
177\r
178Routine Description:\r
179\r
180 TODO: Add function description\r
181\r
182Arguments:\r
183\r
184 Private - TODO: add argument description\r
185\r
186Returns:\r
187\r
188 TODO: add return values\r
189\r
190--*/\r
191{\r
a550d468
MK
192 EFI_BLOCK_IO_MEDIA *Media;\r
193 EFI_STATUS Status;\r
8f819697
RN
194\r
195 Media = Private->Media;\r
196\r
197 switch (GetLastError ()) {\r
a550d468
MK
198 case ERROR_NOT_READY:\r
199 Media->ReadOnly = FALSE;\r
200 Media->MediaPresent = FALSE;\r
201 Status = EFI_NO_MEDIA;\r
202 break;\r
203\r
204 case ERROR_WRONG_DISK:\r
205 Media->ReadOnly = FALSE;\r
206 Media->MediaPresent = TRUE;\r
207 Media->MediaId++;\r
208 Status = EFI_MEDIA_CHANGED;\r
209 break;\r
210\r
211 case ERROR_WRITE_PROTECT:\r
212 Media->ReadOnly = TRUE;\r
213 Status = EFI_WRITE_PROTECTED;\r
214 break;\r
215\r
216 default:\r
217 Status = EFI_DEVICE_ERROR;\r
218 break;\r
8f819697
RN
219 }\r
220\r
a550d468 221 if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {\r
8f819697
RN
222 WinNtBlockIoReset (&Private->EmuBlockIo, FALSE);\r
223 }\r
224\r
225 return Status;\r
226}\r
227\r
8f819697
RN
228EFI_STATUS\r
229WinNtSignalToken (\r
a550d468
MK
230 IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
231 IN EFI_STATUS Status\r
232 )\r
8f819697
RN
233{\r
234 if (Token != NULL) {\r
235 if (Token->Event != NULL) {\r
236 // Caller is responcible for signaling EFI Event\r
237 Token->TransactionStatus = Status;\r
238 return EFI_SUCCESS;\r
239 }\r
240 }\r
a550d468 241\r
8f819697
RN
242 return Status;\r
243}\r
244\r
245/**\r
246 Read BufferSize bytes from Lba into Buffer.\r
247\r
248 This function reads the requested number of blocks from the device. All the\r
249 blocks are read, or an error is returned.\r
250 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and\r
251 non-blocking I/O is being used, the Event associated with this request will\r
252 not be signaled.\r
253\r
254 @param[in] This Indicates a pointer to the calling context.\r
255 @param[in] MediaId Id of the media, changes every time the media is\r
256 replaced.\r
257 @param[in] Lba The starting Logical Block Address to read from.\r
79e4f2a5 258 @param[in, out] Token A pointer to the token associated with the transaction.\r
8f819697
RN
259 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
260 @param[out] Buffer A pointer to the destination buffer for the data. The\r
261 caller is responsible for either having implicit or\r
262 explicit ownership of the buffer.\r
263\r
264 @retval EFI_SUCCESS The read request was queued if Token->Event is\r
265 not NULL.The data was read correctly from the\r
266 device if the Token->Event is NULL.\r
267 @retval EFI_DEVICE_ERROR The device reported an error while performing\r
268 the read.\r
269 @retval EFI_NO_MEDIA There is no media in the device.\r
270 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
271 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the\r
272 intrinsic block size of the device.\r
273 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
274 or the buffer is not on proper alignment.\r
275 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
276 of resources.\r
277**/\r
278EFI_STATUS\r
279WinNtBlockIoReadBlocks (\r
280 IN EMU_BLOCK_IO_PROTOCOL *This,\r
281 IN UINT32 MediaId,\r
282 IN EFI_LBA Lba,\r
283 IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
284 IN UINTN BufferSize,\r
a550d468 285 OUT VOID *Buffer\r
8f819697
RN
286 )\r
287{\r
a550d468
MK
288 WIN_NT_BLOCK_IO_PRIVATE *Private;\r
289 BOOL Flag;\r
290 EFI_STATUS Status;\r
291 DWORD BytesRead;\r
292 UINT64 DistanceToMove;\r
293 UINT64 DistanceMoved;\r
8f819697
RN
294\r
295 Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r
296\r
297 //\r
298 // Seek to proper position\r
299 //\r
300 DistanceToMove = MultU64x32 (Lba, (UINT32)Private->BlockSize);\r
a550d468 301 Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, FILE_BEGIN);\r
8f819697
RN
302\r
303 if (EFI_ERROR (Status) || (DistanceToMove != DistanceMoved)) {\r
9c7da8d8 304 DEBUG ((DEBUG_INIT, "ReadBlocks: SetFilePointer failed\n"));\r
8f819697
RN
305 return WinNtBlockIoError (Private->Media);\r
306 }\r
307\r
308 Flag = ReadFile (Private->NtHandle, Buffer, (DWORD)BufferSize, (LPDWORD)&BytesRead, NULL);\r
309 if (!Flag || (BytesRead != BufferSize)) {\r
310 return WinNtBlockIoError (Private->Media);\r
311 }\r
312\r
313 Private->Media->MediaPresent = TRUE;\r
314 return WinNtSignalToken (Token, EFI_SUCCESS);\r
315}\r
316\r
8f819697
RN
317/**\r
318 Write BufferSize bytes from Lba into Buffer.\r
319\r
320 This function writes the requested number of blocks to the device. All blocks\r
321 are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,\r
322 EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is\r
323 being used, the Event associated with this request will not be signaled.\r
324\r
325 @param[in] This Indicates a pointer to the calling context.\r
326 @param[in] MediaId The media ID that the write request is for.\r
327 @param[in] Lba The starting logical block address to be written. The\r
328 caller is responsible for writing to only legitimate\r
329 locations.\r
330 @param[in, out] Token A pointer to the token associated with the transaction.\r
331 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r
332 @param[in] Buffer A pointer to the source buffer for the data.\r
333\r
334 @retval EFI_SUCCESS The write request was queued if Event is not NULL.\r
335 The data was written correctly to the device if\r
336 the Event is NULL.\r
337 @retval EFI_WRITE_PROTECTED The device can not be written to.\r
338 @retval EFI_NO_MEDIA There is no media in the device.\r
3d6b7fd3 339 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.\r
8f819697
RN
340 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
341 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
342 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
343 or the buffer is not on proper alignment.\r
344 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
345 of resources.\r
346\r
347**/\r
348EFI_STATUS\r
349WinNtBlockIoWriteBlocks (\r
350 IN EMU_BLOCK_IO_PROTOCOL *This,\r
351 IN UINT32 MediaId,\r
352 IN EFI_LBA Lba,\r
353 IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
354 IN UINTN BufferSize,\r
355 IN VOID *Buffer\r
356 )\r
357{\r
a550d468
MK
358 WIN_NT_BLOCK_IO_PRIVATE *Private;\r
359 UINTN BytesWritten;\r
360 BOOL Success;\r
361 EFI_STATUS Status;\r
362 UINT64 DistanceToMove;\r
363 UINT64 DistanceMoved;\r
8f819697
RN
364\r
365 Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r
366\r
367 //\r
368 // Seek to proper position\r
369 //\r
370 DistanceToMove = MultU64x32 (Lba, (UINT32)Private->BlockSize);\r
a550d468 371 Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, FILE_BEGIN);\r
8f819697
RN
372\r
373 if (EFI_ERROR (Status) || (DistanceToMove != DistanceMoved)) {\r
9c7da8d8 374 DEBUG ((DEBUG_INIT, "WriteBlocks: SetFilePointer failed\n"));\r
8f819697
RN
375 return WinNtBlockIoError (Private->Media);\r
376 }\r
377\r
378 Success = WriteFile (Private->NtHandle, Buffer, (DWORD)BufferSize, (LPDWORD)&BytesWritten, NULL);\r
379 if (!Success || (BytesWritten != BufferSize)) {\r
380 return WinNtBlockIoError (Private->Media);\r
381 }\r
382\r
383 //\r
384 // If the write succeeded, we are not write protected and media is present.\r
385 //\r
386 Private->Media->MediaPresent = TRUE;\r
387 Private->Media->ReadOnly = FALSE;\r
388 return WinNtSignalToken (Token, EFI_SUCCESS);\r
389}\r
390\r
391/**\r
392 Flush the Block Device.\r
393\r
394 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED\r
395 is returned and non-blocking I/O is being used, the Event associated with\r
396 this request will not be signaled.\r
397\r
398 @param[in] This Indicates a pointer to the calling context.\r
399 @param[in,out] Token A pointer to the token associated with the transaction\r
400\r
401 @retval EFI_SUCCESS The flush request was queued if Event is not NULL.\r
402 All outstanding data was written correctly to the\r
403 device if the Event is NULL.\r
3d6b7fd3 404 @retval EFI_DEVICE_ERROR The device reported an error while writing back\r
8f819697
RN
405 the data.\r
406 @retval EFI_WRITE_PROTECTED The device cannot be written to.\r
407 @retval EFI_NO_MEDIA There is no media in the device.\r
408 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
409 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
410 of resources.\r
411\r
412**/\r
413EFI_STATUS\r
414WinNtBlockIoFlushBlocks (\r
a550d468
MK
415 IN EMU_BLOCK_IO_PROTOCOL *This,\r
416 IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
8f819697
RN
417 )\r
418{\r
419 return WinNtSignalToken (Token, EFI_SUCCESS);\r
420}\r
421\r
8f819697
RN
422/**\r
423 Reset the block device hardware.\r
424\r
425 @param[in] This Indicates a pointer to the calling context.\r
426 @param[in] ExtendedVerification Indicates that the driver may perform a more\r
427 exhausive verfication operation of the device\r
428 during reset.\r
429\r
430 @retval EFI_SUCCESS The device was reset.\r
431 @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
432 not be reset.\r
433\r
434**/\r
435EFI_STATUS\r
436WinNtBlockIoReset (\r
a550d468
MK
437 IN EMU_BLOCK_IO_PROTOCOL *This,\r
438 IN BOOLEAN ExtendedVerification\r
8f819697
RN
439 )\r
440{\r
a550d468 441 WIN_NT_BLOCK_IO_PRIVATE *Private;\r
8f819697
RN
442\r
443 Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r
444\r
445 if (Private->NtHandle != INVALID_HANDLE_VALUE) {\r
446 CloseHandle (Private->NtHandle);\r
447 Private->NtHandle = INVALID_HANDLE_VALUE;\r
448 }\r
449\r
450 return EFI_SUCCESS;\r
451}\r
452\r
a550d468 453EMU_BLOCK_IO_PROTOCOL gEmuBlockIoProtocol = {\r
8f819697
RN
454 WinNtBlockIoReset,\r
455 WinNtBlockIoReadBlocks,\r
456 WinNtBlockIoWriteBlocks,\r
457 WinNtBlockIoFlushBlocks,\r
458 WinNtBlockIoCreateMapping\r
459};\r
460\r
461EFI_STATUS\r
462EFIAPI\r
463WinNtBlockIoThunkOpen (\r
a550d468 464 IN EMU_IO_THUNK_PROTOCOL *This\r
8f819697
RN
465 )\r
466{\r
467 WIN_NT_BLOCK_IO_PRIVATE *Private;\r
468 CHAR16 *Str;\r
469\r
470 Private = AllocatePool (sizeof (*Private));\r
471 if (Private == NULL) {\r
472 return EFI_OUT_OF_RESOURCES;\r
473 }\r
474\r
475 Private->Signature = WIN_NT_BLOCK_IO_PRIVATE_SIGNATURE;\r
476 Private->Thunk = This;\r
477 CopyMem (&Private->EmuBlockIo, &gEmuBlockIoProtocol, sizeof (gEmuBlockIoProtocol));\r
478 Private->BlockSize = 512;\r
a550d468 479 Private->NtHandle = INVALID_HANDLE_VALUE;\r
8f819697
RN
480\r
481 Private->FileName = AllocateCopyPool (StrSize (This->ConfigString), This->ConfigString);\r
482 if (Private->FileName == NULL) {\r
483 return EFI_OUT_OF_RESOURCES;\r
484 }\r
a550d468 485\r
8f819697
RN
486 //\r
487 // Parse ConfigString\r
488 // <ConfigString> := <FileName> ':' [RF][OW] ':' <BlockSize>\r
489 //\r
490 Str = StrStr (Private->FileName, L":");\r
491 if (Str == NULL) {\r
492 Private->Removable = FALSE;\r
493 Private->Readonly = FALSE;\r
494 } else {\r
495 for (*Str++ = L'\0'; *Str != L'\0'; Str++) {\r
a550d468
MK
496 if ((*Str == 'R') || (*Str == 'F')) {\r
497 Private->Removable = (BOOLEAN)(*Str == L'R');\r
8f819697 498 }\r
a550d468
MK
499\r
500 if ((*Str == 'O') || (*Str == 'W')) {\r
501 Private->Readonly = (BOOLEAN)(*Str == L'O');\r
8f819697 502 }\r
a550d468 503\r
8f819697
RN
504 if (*Str == ':') {\r
505 Private->BlockSize = wcstol (++Str, NULL, 0);\r
506 break;\r
507 }\r
508 }\r
509 }\r
510\r
511 This->Interface = &Private->EmuBlockIo;\r
512 This->Private = Private;\r
513 return EFI_SUCCESS;\r
514}\r
515\r
8f819697
RN
516EFI_STATUS\r
517EFIAPI\r
518WinNtBlockIoThunkClose (\r
a550d468 519 IN EMU_IO_THUNK_PROTOCOL *This\r
8f819697
RN
520 )\r
521{\r
522 WIN_NT_BLOCK_IO_PRIVATE *Private;\r
523\r
524 Private = This->Private;\r
525\r
526 if (Private != NULL) {\r
527 if (Private->FileName != NULL) {\r
528 FreePool (Private->FileName);\r
529 }\r
a550d468 530\r
8f819697
RN
531 FreePool (Private);\r
532 }\r
533\r
534 return EFI_SUCCESS;\r
535}\r
536\r
a550d468 537EMU_IO_THUNK_PROTOCOL mWinNtBlockIoThunkIo = {\r
8f819697
RN
538 &gEmuBlockIoProtocolGuid,\r
539 NULL,\r
540 NULL,\r
541 0,\r
542 WinNtBlockIoThunkOpen,\r
543 WinNtBlockIoThunkClose,\r
544 NULL\r
545};\r