3 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
4 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #define WIN_NT_BLOCK_IO_PRIVATE_SIGNATURE SIGNATURE_32 ('N', 'T', 'b', 'k')
14 EMU_IO_THUNK_PROTOCOL
*Thunk
;
23 EFI_BLOCK_IO_MEDIA
*Media
;
24 EMU_BLOCK_IO_PROTOCOL EmuBlockIo
;
25 } WIN_NT_BLOCK_IO_PRIVATE
;
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)
33 IN EMU_BLOCK_IO_PROTOCOL
*This
,
34 IN BOOLEAN ExtendedVerification
42 IN WIN_NT_BLOCK_IO_PRIVATE
*Private
,
43 IN INT64 DistanceToMove
,
44 OUT UINT64
*NewFilePointer
,
49 This function extends the capability of SetFilePointer to accept 64 bit parameters
54 LARGE_INTEGER LargeInt
;
56 LargeInt
.QuadPart
= DistanceToMove
;
59 LargeInt
.LowPart
= SetFilePointer (
66 if (LargeInt
.LowPart
== -1 && GetLastError () != NO_ERROR
) {
67 Status
= EFI_INVALID_PARAMETER
;
70 if (NewFilePointer
!= NULL
) {
71 *NewFilePointer
= LargeInt
.QuadPart
;
80 WinNtBlockIoOpenDevice (
81 IN WIN_NT_BLOCK_IO_PRIVATE
*Private
,
82 IN EFI_BLOCK_IO_MEDIA
*Media
89 // If the device is already opened, close it
91 if (Private
->NtHandle
!= INVALID_HANDLE_VALUE
) {
92 WinNtBlockIoReset (&Private
->EmuBlockIo
, FALSE
);
98 Private
->NtHandle
= CreateFile (
100 GENERIC_READ
| (Private
->Readonly
? 0 : GENERIC_WRITE
),
101 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
103 OPEN_ALWAYS
, // Create if it doesn't exist
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
;
116 // get the size of the file
118 Status
= SetFilePointer64 (Private
, 0, &FileSize
, FILE_END
);
120 if (EFI_ERROR (Status
)) {
121 DEBUG ((EFI_D_ERROR
, "OpenBlock: Could not get filesize of %s\n", Private
->FileName
));
122 Status
= EFI_UNSUPPORTED
;
126 Media
->LastBlock
= DivU64x32 (FileSize
, (UINT32
)Private
->BlockSize
) - 1;
128 DEBUG ((EFI_D_INIT
, "OpenBlock: opened %S\n", Private
->FileName
));
129 Status
= EFI_SUCCESS
;
132 if (EFI_ERROR (Status
)) {
133 if (Private
->NtHandle
!= INVALID_HANDLE_VALUE
) {
134 WinNtBlockIoReset (&Private
->EmuBlockIo
, FALSE
);
144 WinNtBlockIoCreateMapping (
145 IN EMU_BLOCK_IO_PROTOCOL
*This
,
146 IN EFI_BLOCK_IO_MEDIA
*Media
149 WIN_NT_BLOCK_IO_PRIVATE
*Private
;
151 Private
= WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This
);
154 Media
->RemovableMedia
= Private
->Removable
;
155 Media
->MediaPresent
= TRUE
;
156 Media
->LogicalPartition
= FALSE
;
157 Media
->ReadOnly
= Private
->Readonly
;
158 Media
->WriteCaching
= FALSE
;
160 Media
->LastBlock
= 0; // Filled in by OpenDevice
161 Media
->BlockSize
= Private
->BlockSize
;
163 // EFI_BLOCK_IO_PROTOCOL_REVISION2
164 Media
->LowestAlignedLba
= 0;
165 Media
->LogicalBlocksPerPhysicalBlock
= 0;
168 // EFI_BLOCK_IO_PROTOCOL_REVISION3
169 Media
->OptimalTransferLengthGranularity
= 0;
172 // Remember the Media pointer.
174 Private
->Media
= Media
;
175 return WinNtBlockIoOpenDevice (Private
, Media
);
182 IN WIN_NT_BLOCK_IO_PRIVATE
*Private
188 TODO: Add function description
192 Private - TODO: add argument description
196 TODO: add return values
200 EFI_BLOCK_IO_MEDIA
*Media
;
203 Media
= Private
->Media
;
205 switch (GetLastError ()) {
207 case ERROR_NOT_READY
:
208 Media
->ReadOnly
= FALSE
;
209 Media
->MediaPresent
= FALSE
;
210 Status
= EFI_NO_MEDIA
;
213 case ERROR_WRONG_DISK
:
214 Media
->ReadOnly
= FALSE
;
215 Media
->MediaPresent
= TRUE
;
217 Status
= EFI_MEDIA_CHANGED
;
220 case ERROR_WRITE_PROTECT
:
221 Media
->ReadOnly
= TRUE
;
222 Status
= EFI_WRITE_PROTECTED
;
226 Status
= EFI_DEVICE_ERROR
;
230 if (Status
== EFI_NO_MEDIA
|| Status
== EFI_MEDIA_CHANGED
) {
231 WinNtBlockIoReset (&Private
->EmuBlockIo
, FALSE
);
240 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
245 if (Token
->Event
!= NULL
) {
246 // Caller is responcible for signaling EFI Event
247 Token
->TransactionStatus
= Status
;
255 Read BufferSize bytes from Lba into Buffer.
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
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
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.
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
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
288 WinNtBlockIoReadBlocks (
289 IN EMU_BLOCK_IO_PROTOCOL
*This
,
292 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
297 WIN_NT_BLOCK_IO_PRIVATE
*Private
;
301 UINT64 DistanceToMove
;
302 UINT64 DistanceMoved
;
304 Private
= WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This
);
307 // Seek to proper position
309 DistanceToMove
= MultU64x32 (Lba
, (UINT32
)Private
->BlockSize
);
310 Status
= SetFilePointer64 (Private
, DistanceToMove
, &DistanceMoved
, FILE_BEGIN
);
312 if (EFI_ERROR (Status
) || (DistanceToMove
!= DistanceMoved
)) {
313 DEBUG ((EFI_D_INIT
, "ReadBlocks: SetFilePointer failed\n"));
314 return WinNtBlockIoError (Private
->Media
);
317 Flag
= ReadFile (Private
->NtHandle
, Buffer
, (DWORD
)BufferSize
, (LPDWORD
)&BytesRead
, NULL
);
318 if (!Flag
|| (BytesRead
!= BufferSize
)) {
319 return WinNtBlockIoError (Private
->Media
);
322 Private
->Media
->MediaPresent
= TRUE
;
323 return WinNtSignalToken (Token
, EFI_SUCCESS
);
328 Write BufferSize bytes from Lba into Buffer.
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.
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
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.
344 @retval EFI_SUCCESS The write request was queued if Event is not NULL.
345 The data was written correctly to the device if
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_CHNAGED The MediaId does not matched 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
359 WinNtBlockIoWriteBlocks (
360 IN EMU_BLOCK_IO_PROTOCOL
*This
,
363 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
368 WIN_NT_BLOCK_IO_PRIVATE
*Private
;
372 UINT64 DistanceToMove
;
373 UINT64 DistanceMoved
;
375 Private
= WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This
);
378 // Seek to proper position
380 DistanceToMove
= MultU64x32 (Lba
, (UINT32
)Private
->BlockSize
);
381 Status
= SetFilePointer64 (Private
, DistanceToMove
, &DistanceMoved
, FILE_BEGIN
);
383 if (EFI_ERROR (Status
) || (DistanceToMove
!= DistanceMoved
)) {
384 DEBUG ((EFI_D_INIT
, "WriteBlocks: SetFilePointer failed\n"));
385 return WinNtBlockIoError (Private
->Media
);
388 Success
= WriteFile (Private
->NtHandle
, Buffer
, (DWORD
)BufferSize
, (LPDWORD
)&BytesWritten
, NULL
);
389 if (!Success
|| (BytesWritten
!= BufferSize
)) {
390 return WinNtBlockIoError (Private
->Media
);
394 // If the write succeeded, we are not write protected and media is present.
396 Private
->Media
->MediaPresent
= TRUE
;
397 Private
->Media
->ReadOnly
= FALSE
;
398 return WinNtSignalToken (Token
, EFI_SUCCESS
);
402 Flush the Block Device.
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.
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
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 writting back
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
424 WinNtBlockIoFlushBlocks (
425 IN EMU_BLOCK_IO_PROTOCOL
*This
,
426 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
429 return WinNtSignalToken (Token
, EFI_SUCCESS
);
434 Reset the block device hardware.
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
441 @retval EFI_SUCCESS The device was reset.
442 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
448 IN EMU_BLOCK_IO_PROTOCOL
*This
,
449 IN BOOLEAN ExtendedVerification
452 WIN_NT_BLOCK_IO_PRIVATE
*Private
;
454 Private
= WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This
);
456 if (Private
->NtHandle
!= INVALID_HANDLE_VALUE
) {
457 CloseHandle (Private
->NtHandle
);
458 Private
->NtHandle
= INVALID_HANDLE_VALUE
;
464 EMU_BLOCK_IO_PROTOCOL gEmuBlockIoProtocol
= {
466 WinNtBlockIoReadBlocks
,
467 WinNtBlockIoWriteBlocks
,
468 WinNtBlockIoFlushBlocks
,
469 WinNtBlockIoCreateMapping
474 WinNtBlockIoThunkOpen (
475 IN EMU_IO_THUNK_PROTOCOL
*This
478 WIN_NT_BLOCK_IO_PRIVATE
*Private
;
481 Private
= AllocatePool (sizeof (*Private
));
482 if (Private
== NULL
) {
483 return EFI_OUT_OF_RESOURCES
;
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
;
492 Private
->FileName
= AllocateCopyPool (StrSize (This
->ConfigString
), This
->ConfigString
);
493 if (Private
->FileName
== NULL
) {
494 return EFI_OUT_OF_RESOURCES
;
497 // Parse ConfigString
498 // <ConfigString> := <FileName> ':' [RF][OW] ':' <BlockSize>
500 Str
= StrStr (Private
->FileName
, L
":");
502 Private
->Removable
= FALSE
;
503 Private
->Readonly
= FALSE
;
505 for (*Str
++ = L
'\0'; *Str
!= L
'\0'; Str
++) {
506 if (*Str
== 'R' || *Str
== 'F') {
507 Private
->Removable
= (BOOLEAN
) (*Str
== L
'R');
509 if (*Str
== 'O' || *Str
== 'W') {
510 Private
->Readonly
= (BOOLEAN
) (*Str
== L
'O');
513 Private
->BlockSize
= wcstol (++Str
, NULL
, 0);
519 This
->Interface
= &Private
->EmuBlockIo
;
520 This
->Private
= Private
;
527 WinNtBlockIoThunkClose (
528 IN EMU_IO_THUNK_PROTOCOL
*This
531 WIN_NT_BLOCK_IO_PRIVATE
*Private
;
533 Private
= This
->Private
;
535 if (Private
!= NULL
) {
536 if (Private
->FileName
!= NULL
) {
537 FreePool (Private
->FileName
);
547 EMU_IO_THUNK_PROTOCOL mWinNtBlockIoThunkIo
= {
548 &gEmuBlockIoProtocolGuid
,
552 WinNtBlockIoThunkOpen
,
553 WinNtBlockIoThunkClose
,