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