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