]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - EmulatorPkg/Win/Host/WinBlockIo.c
EmulatorPkg: Apply uncrustify changes
[mirror_edk2.git] / EmulatorPkg / Win / Host / WinBlockIo.c
... / ...
CommitLineData
1/**@file\r
2\r
3Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
4SPDX-License-Identifier: BSD-2-Clause-Patent\r
5\r
6**/\r
7\r
8#include "WinHost.h"\r
9\r
10#define WIN_NT_BLOCK_IO_PRIVATE_SIGNATURE SIGNATURE_32 ('N', 'T', 'b', 'k')\r
11typedef struct {\r
12 UINTN Signature;\r
13\r
14 EMU_IO_THUNK_PROTOCOL *Thunk;\r
15\r
16 CHAR16 *FileName;\r
17 BOOLEAN Removable;\r
18 BOOLEAN Readonly;\r
19\r
20 HANDLE NtHandle;\r
21 UINT32 BlockSize;\r
22\r
23 EFI_BLOCK_IO_MEDIA *Media;\r
24 EMU_BLOCK_IO_PROTOCOL EmuBlockIo;\r
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
30EFI_STATUS\r
31WinNtBlockIoReset (\r
32 IN EMU_BLOCK_IO_PROTOCOL *This,\r
33 IN BOOLEAN ExtendedVerification\r
34 );\r
35\r
36EFI_STATUS\r
37SetFilePointer64 (\r
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
44/*++\r
45\r
46This function extends the capability of SetFilePointer to accept 64 bit parameters\r
47\r
48--*/\r
49{\r
50 EFI_STATUS Status;\r
51 LARGE_INTEGER LargeInt;\r
52\r
53 LargeInt.QuadPart = DistanceToMove;\r
54 Status = EFI_SUCCESS;\r
55\r
56 LargeInt.LowPart = SetFilePointer (\r
57 Private->NtHandle,\r
58 LargeInt.LowPart,\r
59 &LargeInt.HighPart,\r
60 MoveMethod\r
61 );\r
62\r
63 if ((LargeInt.LowPart == -1) && (GetLastError () != NO_ERROR)) {\r
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
74EFI_STATUS\r
75WinNtBlockIoOpenDevice (\r
76 IN WIN_NT_BLOCK_IO_PRIVATE *Private,\r
77 IN EFI_BLOCK_IO_MEDIA *Media\r
78 )\r
79{\r
80 EFI_STATUS Status;\r
81 UINT64 FileSize;\r
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
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
102\r
103 if (Private->NtHandle == INVALID_HANDLE_VALUE) {\r
104 DEBUG ((DEBUG_INFO, "OpenBlock: Could not open %S, %x\n", Private->FileName, GetLastError ()));\r
105 Media->MediaPresent = FALSE;\r
106 Status = EFI_NO_MEDIA;\r
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
116 DEBUG ((DEBUG_ERROR, "OpenBlock: Could not get filesize of %s\n", Private->FileName));\r
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
123 DEBUG ((DEBUG_INIT, "OpenBlock: opened %S\n", Private->FileName));\r
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
136EFI_STATUS\r
137EFIAPI\r
138WinNtBlockIoCreateMapping (\r
139 IN EMU_BLOCK_IO_PROTOCOL *This,\r
140 IN EFI_BLOCK_IO_MEDIA *Media\r
141 )\r
142{\r
143 WIN_NT_BLOCK_IO_PRIVATE *Private;\r
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
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
171EFI_STATUS\r
172WinNtBlockIoError (\r
173 IN WIN_NT_BLOCK_IO_PRIVATE *Private\r
174 )\r
175\r
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
192 EFI_BLOCK_IO_MEDIA *Media;\r
193 EFI_STATUS Status;\r
194\r
195 Media = Private->Media;\r
196\r
197 switch (GetLastError ()) {\r
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
219 }\r
220\r
221 if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {\r
222 WinNtBlockIoReset (&Private->EmuBlockIo, FALSE);\r
223 }\r
224\r
225 return Status;\r
226}\r
227\r
228EFI_STATUS\r
229WinNtSignalToken (\r
230 IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
231 IN EFI_STATUS Status\r
232 )\r
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
241\r
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
258 @param[in, out] Token A pointer to the token associated with the transaction.\r
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
285 OUT VOID *Buffer\r
286 )\r
287{\r
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
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
301 Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, FILE_BEGIN);\r
302\r
303 if (EFI_ERROR (Status) || (DistanceToMove != DistanceMoved)) {\r
304 DEBUG ((DEBUG_INIT, "ReadBlocks: SetFilePointer failed\n"));\r
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
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
339 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.\r
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
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
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
371 Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, FILE_BEGIN);\r
372\r
373 if (EFI_ERROR (Status) || (DistanceToMove != DistanceMoved)) {\r
374 DEBUG ((DEBUG_INIT, "WriteBlocks: SetFilePointer failed\n"));\r
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
404 @retval EFI_DEVICE_ERROR The device reported an error while writing back\r
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
415 IN EMU_BLOCK_IO_PROTOCOL *This,\r
416 IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
417 )\r
418{\r
419 return WinNtSignalToken (Token, EFI_SUCCESS);\r
420}\r
421\r
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
437 IN EMU_BLOCK_IO_PROTOCOL *This,\r
438 IN BOOLEAN ExtendedVerification\r
439 )\r
440{\r
441 WIN_NT_BLOCK_IO_PRIVATE *Private;\r
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
453EMU_BLOCK_IO_PROTOCOL gEmuBlockIoProtocol = {\r
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
464 IN EMU_IO_THUNK_PROTOCOL *This\r
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
479 Private->NtHandle = INVALID_HANDLE_VALUE;\r
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
485\r
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
496 if ((*Str == 'R') || (*Str == 'F')) {\r
497 Private->Removable = (BOOLEAN)(*Str == L'R');\r
498 }\r
499\r
500 if ((*Str == 'O') || (*Str == 'W')) {\r
501 Private->Readonly = (BOOLEAN)(*Str == L'O');\r
502 }\r
503\r
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
516EFI_STATUS\r
517EFIAPI\r
518WinNtBlockIoThunkClose (\r
519 IN EMU_IO_THUNK_PROTOCOL *This\r
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
530\r
531 FreePool (Private);\r
532 }\r
533\r
534 return EFI_SUCCESS;\r
535}\r
536\r
537EMU_IO_THUNK_PROTOCOL mWinNtBlockIoThunkIo = {\r
538 &gEmuBlockIoProtocolGuid,\r
539 NULL,\r
540 NULL,\r
541 0,\r
542 WinNtBlockIoThunkOpen,\r
543 WinNtBlockIoThunkClose,\r
544 NULL\r
545};\r