EmulatorPkg/Win: Fix various typos
[mirror_edk2.git] / EmulatorPkg / Win / Host / WinBlockIo.c
1 /**@file\r
2 \r
3 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
4 SPDX-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
11 typedef 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
30 \r
31 EFI_STATUS\r
32 WinNtBlockIoReset (\r
33   IN EMU_BLOCK_IO_PROTOCOL    *This,\r
34   IN BOOLEAN                  ExtendedVerification\r
35   );\r
36 \r
37 \r
38 \r
39 \r
40 EFI_STATUS\r
41 SetFilePointer64 (\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
49 This 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
79 EFI_STATUS\r
80 WinNtBlockIoOpenDevice (\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
131 Done:\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
142 EFI_STATUS\r
143 EFIAPI\r
144 WinNtBlockIoCreateMapping (\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
180 EFI_STATUS\r
181 WinNtBlockIoError (\r
182   IN WIN_NT_BLOCK_IO_PRIVATE      *Private\r
183 )\r
184 /*++\r
185 \r
186 Routine Description:\r
187 \r
188   TODO: Add function description\r
189 \r
190 Arguments:\r
191 \r
192   Private - TODO: add argument description\r
193 \r
194 Returns:\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
238 EFI_STATUS\r
239 WinNtSignalToken (\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
267   @param[in, out]  Token      A pointer to the token associated with the transaction.\r
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
287 EFI_STATUS\r
288 WinNtBlockIoReadBlocks (\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
349   @retval EFI_MEDIA_CHANGED     The MediaId does not match the current device.\r
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
358 EFI_STATUS\r
359 WinNtBlockIoWriteBlocks (\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
414   @retval EFI_DEVICE_ERROR     The device reported an error while writing back\r
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
423 EFI_STATUS\r
424 WinNtBlockIoFlushBlocks (\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
446 EFI_STATUS\r
447 WinNtBlockIoReset (\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
464 EMU_BLOCK_IO_PROTOCOL gEmuBlockIoProtocol = {\r
465   WinNtBlockIoReset,\r
466   WinNtBlockIoReadBlocks,\r
467   WinNtBlockIoWriteBlocks,\r
468   WinNtBlockIoFlushBlocks,\r
469   WinNtBlockIoCreateMapping\r
470 };\r
471 \r
472 EFI_STATUS\r
473 EFIAPI\r
474 WinNtBlockIoThunkOpen (\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
525 EFI_STATUS\r
526 EFIAPI\r
527 WinNtBlockIoThunkClose (\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
547 EMU_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