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)
32 IN EMU_BLOCK_IO_PROTOCOL
*This
,
33 IN BOOLEAN ExtendedVerification
38 IN WIN_NT_BLOCK_IO_PRIVATE
*Private
,
39 IN INT64 DistanceToMove
,
40 OUT UINT64
*NewFilePointer
,
46 This function extends the capability of SetFilePointer to accept 64 bit parameters
51 LARGE_INTEGER LargeInt
;
53 LargeInt
.QuadPart
= DistanceToMove
;
56 LargeInt
.LowPart
= SetFilePointer (
63 if ((LargeInt
.LowPart
== -1) && (GetLastError () != NO_ERROR
)) {
64 Status
= EFI_INVALID_PARAMETER
;
67 if (NewFilePointer
!= NULL
) {
68 *NewFilePointer
= LargeInt
.QuadPart
;
75 WinNtBlockIoOpenDevice (
76 IN WIN_NT_BLOCK_IO_PRIVATE
*Private
,
77 IN EFI_BLOCK_IO_MEDIA
*Media
84 // If the device is already opened, close it
86 if (Private
->NtHandle
!= INVALID_HANDLE_VALUE
) {
87 WinNtBlockIoReset (&Private
->EmuBlockIo
, FALSE
);
93 Private
->NtHandle
= CreateFile (
95 GENERIC_READ
| (Private
->Readonly
? 0 : GENERIC_WRITE
),
96 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
98 OPEN_ALWAYS
, // Create if it doesn't exist
103 if (Private
->NtHandle
== INVALID_HANDLE_VALUE
) {
104 DEBUG ((DEBUG_INFO
, "OpenBlock: Could not open %S, %x\n", Private
->FileName
, GetLastError ()));
105 Media
->MediaPresent
= FALSE
;
106 Status
= EFI_NO_MEDIA
;
111 // get the size of the file
113 Status
= SetFilePointer64 (Private
, 0, &FileSize
, FILE_END
);
115 if (EFI_ERROR (Status
)) {
116 DEBUG ((DEBUG_ERROR
, "OpenBlock: Could not get filesize of %s\n", Private
->FileName
));
117 Status
= EFI_UNSUPPORTED
;
121 Media
->LastBlock
= DivU64x32 (FileSize
, (UINT32
)Private
->BlockSize
) - 1;
123 DEBUG ((DEBUG_INIT
, "OpenBlock: opened %S\n", Private
->FileName
));
124 Status
= EFI_SUCCESS
;
127 if (EFI_ERROR (Status
)) {
128 if (Private
->NtHandle
!= INVALID_HANDLE_VALUE
) {
129 WinNtBlockIoReset (&Private
->EmuBlockIo
, FALSE
);
138 WinNtBlockIoCreateMapping (
139 IN EMU_BLOCK_IO_PROTOCOL
*This
,
140 IN EFI_BLOCK_IO_MEDIA
*Media
143 WIN_NT_BLOCK_IO_PRIVATE
*Private
;
145 Private
= WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This
);
148 Media
->RemovableMedia
= Private
->Removable
;
149 Media
->MediaPresent
= TRUE
;
150 Media
->LogicalPartition
= FALSE
;
151 Media
->ReadOnly
= Private
->Readonly
;
152 Media
->WriteCaching
= FALSE
;
154 Media
->LastBlock
= 0; // Filled in by OpenDevice
155 Media
->BlockSize
= Private
->BlockSize
;
157 // EFI_BLOCK_IO_PROTOCOL_REVISION2
158 Media
->LowestAlignedLba
= 0;
159 Media
->LogicalBlocksPerPhysicalBlock
= 0;
161 // EFI_BLOCK_IO_PROTOCOL_REVISION3
162 Media
->OptimalTransferLengthGranularity
= 0;
165 // Remember the Media pointer.
167 Private
->Media
= Media
;
168 return WinNtBlockIoOpenDevice (Private
, Media
);
173 IN WIN_NT_BLOCK_IO_PRIVATE
*Private
180 TODO: Add function description
184 Private - TODO: add argument description
188 TODO: add return values
192 EFI_BLOCK_IO_MEDIA
*Media
;
195 Media
= Private
->Media
;
197 switch (GetLastError ()) {
198 case ERROR_NOT_READY
:
199 Media
->ReadOnly
= FALSE
;
200 Media
->MediaPresent
= FALSE
;
201 Status
= EFI_NO_MEDIA
;
204 case ERROR_WRONG_DISK
:
205 Media
->ReadOnly
= FALSE
;
206 Media
->MediaPresent
= TRUE
;
208 Status
= EFI_MEDIA_CHANGED
;
211 case ERROR_WRITE_PROTECT
:
212 Media
->ReadOnly
= TRUE
;
213 Status
= EFI_WRITE_PROTECTED
;
217 Status
= EFI_DEVICE_ERROR
;
221 if ((Status
== EFI_NO_MEDIA
) || (Status
== EFI_MEDIA_CHANGED
)) {
222 WinNtBlockIoReset (&Private
->EmuBlockIo
, FALSE
);
230 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
235 if (Token
->Event
!= NULL
) {
236 // Caller is responcible for signaling EFI Event
237 Token
->TransactionStatus
= Status
;
246 Read BufferSize bytes from Lba into Buffer.
248 This function reads the requested number of blocks from the device. All the
249 blocks are read, or an error is returned.
250 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
251 non-blocking I/O is being used, the Event associated with this request will
254 @param[in] This Indicates a pointer to the calling context.
255 @param[in] MediaId Id of the media, changes every time the media is
257 @param[in] Lba The starting Logical Block Address to read from.
258 @param[in, out] Token A pointer to the token associated with the transaction.
259 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
260 @param[out] Buffer A pointer to the destination buffer for the data. The
261 caller is responsible for either having implicit or
262 explicit ownership of the buffer.
264 @retval EFI_SUCCESS The read request was queued if Token->Event is
265 not NULL.The data was read correctly from the
266 device if the Token->Event is NULL.
267 @retval EFI_DEVICE_ERROR The device reported an error while performing
269 @retval EFI_NO_MEDIA There is no media in the device.
270 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
271 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
272 intrinsic block size of the device.
273 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
274 or the buffer is not on proper alignment.
275 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
279 WinNtBlockIoReadBlocks (
280 IN EMU_BLOCK_IO_PROTOCOL
*This
,
283 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
288 WIN_NT_BLOCK_IO_PRIVATE
*Private
;
292 UINT64 DistanceToMove
;
293 UINT64 DistanceMoved
;
295 Private
= WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This
);
298 // Seek to proper position
300 DistanceToMove
= MultU64x32 (Lba
, (UINT32
)Private
->BlockSize
);
301 Status
= SetFilePointer64 (Private
, DistanceToMove
, &DistanceMoved
, FILE_BEGIN
);
303 if (EFI_ERROR (Status
) || (DistanceToMove
!= DistanceMoved
)) {
304 DEBUG ((DEBUG_INIT
, "ReadBlocks: SetFilePointer failed\n"));
305 return WinNtBlockIoError (Private
->Media
);
308 Flag
= ReadFile (Private
->NtHandle
, Buffer
, (DWORD
)BufferSize
, (LPDWORD
)&BytesRead
, NULL
);
309 if (!Flag
|| (BytesRead
!= BufferSize
)) {
310 return WinNtBlockIoError (Private
->Media
);
313 Private
->Media
->MediaPresent
= TRUE
;
314 return WinNtSignalToken (Token
, EFI_SUCCESS
);
318 Write BufferSize bytes from Lba into Buffer.
320 This function writes the requested number of blocks to the device. All blocks
321 are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
322 EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
323 being used, the Event associated with this request will not be signaled.
325 @param[in] This Indicates a pointer to the calling context.
326 @param[in] MediaId The media ID that the write request is for.
327 @param[in] Lba The starting logical block address to be written. The
328 caller is responsible for writing to only legitimate
330 @param[in, out] Token A pointer to the token associated with the transaction.
331 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
332 @param[in] Buffer A pointer to the source buffer for the data.
334 @retval EFI_SUCCESS The write request was queued if Event is not NULL.
335 The data was written correctly to the device if
337 @retval EFI_WRITE_PROTECTED The device can not be written to.
338 @retval EFI_NO_MEDIA There is no media in the device.
339 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
340 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
341 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
342 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
343 or the buffer is not on proper alignment.
344 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
349 WinNtBlockIoWriteBlocks (
350 IN EMU_BLOCK_IO_PROTOCOL
*This
,
353 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
358 WIN_NT_BLOCK_IO_PRIVATE
*Private
;
362 UINT64 DistanceToMove
;
363 UINT64 DistanceMoved
;
365 Private
= WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This
);
368 // Seek to proper position
370 DistanceToMove
= MultU64x32 (Lba
, (UINT32
)Private
->BlockSize
);
371 Status
= SetFilePointer64 (Private
, DistanceToMove
, &DistanceMoved
, FILE_BEGIN
);
373 if (EFI_ERROR (Status
) || (DistanceToMove
!= DistanceMoved
)) {
374 DEBUG ((DEBUG_INIT
, "WriteBlocks: SetFilePointer failed\n"));
375 return WinNtBlockIoError (Private
->Media
);
378 Success
= WriteFile (Private
->NtHandle
, Buffer
, (DWORD
)BufferSize
, (LPDWORD
)&BytesWritten
, NULL
);
379 if (!Success
|| (BytesWritten
!= BufferSize
)) {
380 return WinNtBlockIoError (Private
->Media
);
384 // If the write succeeded, we are not write protected and media is present.
386 Private
->Media
->MediaPresent
= TRUE
;
387 Private
->Media
->ReadOnly
= FALSE
;
388 return WinNtSignalToken (Token
, EFI_SUCCESS
);
392 Flush the Block Device.
394 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
395 is returned and non-blocking I/O is being used, the Event associated with
396 this request will not be signaled.
398 @param[in] This Indicates a pointer to the calling context.
399 @param[in,out] Token A pointer to the token associated with the transaction
401 @retval EFI_SUCCESS The flush request was queued if Event is not NULL.
402 All outstanding data was written correctly to the
403 device if the Event is NULL.
404 @retval EFI_DEVICE_ERROR The device reported an error while writing back
406 @retval EFI_WRITE_PROTECTED The device cannot be written to.
407 @retval EFI_NO_MEDIA There is no media in the device.
408 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
409 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
414 WinNtBlockIoFlushBlocks (
415 IN EMU_BLOCK_IO_PROTOCOL
*This
,
416 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
419 return WinNtSignalToken (Token
, EFI_SUCCESS
);
423 Reset the block device hardware.
425 @param[in] This Indicates a pointer to the calling context.
426 @param[in] ExtendedVerification Indicates that the driver may perform a more
427 exhausive verfication operation of the device
430 @retval EFI_SUCCESS The device was reset.
431 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
437 IN EMU_BLOCK_IO_PROTOCOL
*This
,
438 IN BOOLEAN ExtendedVerification
441 WIN_NT_BLOCK_IO_PRIVATE
*Private
;
443 Private
= WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This
);
445 if (Private
->NtHandle
!= INVALID_HANDLE_VALUE
) {
446 CloseHandle (Private
->NtHandle
);
447 Private
->NtHandle
= INVALID_HANDLE_VALUE
;
453 EMU_BLOCK_IO_PROTOCOL gEmuBlockIoProtocol
= {
455 WinNtBlockIoReadBlocks
,
456 WinNtBlockIoWriteBlocks
,
457 WinNtBlockIoFlushBlocks
,
458 WinNtBlockIoCreateMapping
463 WinNtBlockIoThunkOpen (
464 IN EMU_IO_THUNK_PROTOCOL
*This
467 WIN_NT_BLOCK_IO_PRIVATE
*Private
;
470 Private
= AllocatePool (sizeof (*Private
));
471 if (Private
== NULL
) {
472 return EFI_OUT_OF_RESOURCES
;
475 Private
->Signature
= WIN_NT_BLOCK_IO_PRIVATE_SIGNATURE
;
476 Private
->Thunk
= This
;
477 CopyMem (&Private
->EmuBlockIo
, &gEmuBlockIoProtocol
, sizeof (gEmuBlockIoProtocol
));
478 Private
->BlockSize
= 512;
479 Private
->NtHandle
= INVALID_HANDLE_VALUE
;
481 Private
->FileName
= AllocateCopyPool (StrSize (This
->ConfigString
), This
->ConfigString
);
482 if (Private
->FileName
== NULL
) {
483 return EFI_OUT_OF_RESOURCES
;
487 // Parse ConfigString
488 // <ConfigString> := <FileName> ':' [RF][OW] ':' <BlockSize>
490 Str
= StrStr (Private
->FileName
, L
":");
492 Private
->Removable
= FALSE
;
493 Private
->Readonly
= FALSE
;
495 for (*Str
++ = L
'\0'; *Str
!= L
'\0'; Str
++) {
496 if ((*Str
== 'R') || (*Str
== 'F')) {
497 Private
->Removable
= (BOOLEAN
)(*Str
== L
'R');
500 if ((*Str
== 'O') || (*Str
== 'W')) {
501 Private
->Readonly
= (BOOLEAN
)(*Str
== L
'O');
505 Private
->BlockSize
= wcstol (++Str
, NULL
, 0);
511 This
->Interface
= &Private
->EmuBlockIo
;
512 This
->Private
= Private
;
518 WinNtBlockIoThunkClose (
519 IN EMU_IO_THUNK_PROTOCOL
*This
522 WIN_NT_BLOCK_IO_PRIVATE
*Private
;
524 Private
= This
->Private
;
526 if (Private
!= NULL
) {
527 if (Private
->FileName
!= NULL
) {
528 FreePool (Private
->FileName
);
537 EMU_IO_THUNK_PROTOCOL mWinNtBlockIoThunkIo
= {
538 &gEmuBlockIoProtocolGuid
,
542 WinNtBlockIoThunkOpen
,
543 WinNtBlockIoThunkClose
,