]> git.proxmox.com Git - mirror_edk2.git/blob - EmulatorPkg/Win/Host/WinBlockIo.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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 EFI_STATUS
31 WinNtBlockIoReset (
32 IN EMU_BLOCK_IO_PROTOCOL *This,
33 IN BOOLEAN ExtendedVerification
34 );
35
36 EFI_STATUS
37 SetFilePointer64 (
38 IN WIN_NT_BLOCK_IO_PRIVATE *Private,
39 IN INT64 DistanceToMove,
40 OUT UINT64 *NewFilePointer,
41 IN DWORD MoveMethod
42 )
43
44 /*++
45
46 This function extends the capability of SetFilePointer to accept 64 bit parameters
47
48 --*/
49 {
50 EFI_STATUS Status;
51 LARGE_INTEGER LargeInt;
52
53 LargeInt.QuadPart = DistanceToMove;
54 Status = EFI_SUCCESS;
55
56 LargeInt.LowPart = SetFilePointer (
57 Private->NtHandle,
58 LargeInt.LowPart,
59 &LargeInt.HighPart,
60 MoveMethod
61 );
62
63 if ((LargeInt.LowPart == -1) && (GetLastError () != NO_ERROR)) {
64 Status = EFI_INVALID_PARAMETER;
65 }
66
67 if (NewFilePointer != NULL) {
68 *NewFilePointer = LargeInt.QuadPart;
69 }
70
71 return Status;
72 }
73
74 EFI_STATUS
75 WinNtBlockIoOpenDevice (
76 IN WIN_NT_BLOCK_IO_PRIVATE *Private,
77 IN EFI_BLOCK_IO_MEDIA *Media
78 )
79 {
80 EFI_STATUS Status;
81 UINT64 FileSize;
82
83 //
84 // If the device is already opened, close it
85 //
86 if (Private->NtHandle != INVALID_HANDLE_VALUE) {
87 WinNtBlockIoReset (&Private->EmuBlockIo, FALSE);
88 }
89
90 //
91 // Open the device
92 //
93 Private->NtHandle = CreateFile (
94 Private->FileName,
95 GENERIC_READ | (Private->Readonly ? 0 : GENERIC_WRITE),
96 FILE_SHARE_READ | FILE_SHARE_WRITE,
97 NULL,
98 OPEN_ALWAYS, // Create if it doesn't exist
99 0,
100 NULL
101 );
102
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;
107 goto Done;
108 }
109
110 //
111 // get the size of the file
112 //
113 Status = SetFilePointer64 (Private, 0, &FileSize, FILE_END);
114
115 if (EFI_ERROR (Status)) {
116 DEBUG ((DEBUG_ERROR, "OpenBlock: Could not get filesize of %s\n", Private->FileName));
117 Status = EFI_UNSUPPORTED;
118 goto Done;
119 }
120
121 Media->LastBlock = DivU64x32 (FileSize, (UINT32)Private->BlockSize) - 1;
122
123 DEBUG ((DEBUG_INIT, "OpenBlock: opened %S\n", Private->FileName));
124 Status = EFI_SUCCESS;
125
126 Done:
127 if (EFI_ERROR (Status)) {
128 if (Private->NtHandle != INVALID_HANDLE_VALUE) {
129 WinNtBlockIoReset (&Private->EmuBlockIo, FALSE);
130 }
131 }
132
133 return Status;
134 }
135
136 EFI_STATUS
137 EFIAPI
138 WinNtBlockIoCreateMapping (
139 IN EMU_BLOCK_IO_PROTOCOL *This,
140 IN EFI_BLOCK_IO_MEDIA *Media
141 )
142 {
143 WIN_NT_BLOCK_IO_PRIVATE *Private;
144
145 Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
146
147 Media->MediaId = 0;
148 Media->RemovableMedia = Private->Removable;
149 Media->MediaPresent = TRUE;
150 Media->LogicalPartition = FALSE;
151 Media->ReadOnly = Private->Readonly;
152 Media->WriteCaching = FALSE;
153 Media->IoAlign = 1;
154 Media->LastBlock = 0; // Filled in by OpenDevice
155 Media->BlockSize = Private->BlockSize;
156
157 // EFI_BLOCK_IO_PROTOCOL_REVISION2
158 Media->LowestAlignedLba = 0;
159 Media->LogicalBlocksPerPhysicalBlock = 0;
160
161 // EFI_BLOCK_IO_PROTOCOL_REVISION3
162 Media->OptimalTransferLengthGranularity = 0;
163
164 //
165 // Remember the Media pointer.
166 //
167 Private->Media = Media;
168 return WinNtBlockIoOpenDevice (Private, Media);
169 }
170
171 EFI_STATUS
172 WinNtBlockIoError (
173 IN WIN_NT_BLOCK_IO_PRIVATE *Private
174 )
175
176 /*++
177
178 Routine Description:
179
180 TODO: Add function description
181
182 Arguments:
183
184 Private - TODO: add argument description
185
186 Returns:
187
188 TODO: add return values
189
190 --*/
191 {
192 EFI_BLOCK_IO_MEDIA *Media;
193 EFI_STATUS Status;
194
195 Media = Private->Media;
196
197 switch (GetLastError ()) {
198 case ERROR_NOT_READY:
199 Media->ReadOnly = FALSE;
200 Media->MediaPresent = FALSE;
201 Status = EFI_NO_MEDIA;
202 break;
203
204 case ERROR_WRONG_DISK:
205 Media->ReadOnly = FALSE;
206 Media->MediaPresent = TRUE;
207 Media->MediaId++;
208 Status = EFI_MEDIA_CHANGED;
209 break;
210
211 case ERROR_WRITE_PROTECT:
212 Media->ReadOnly = TRUE;
213 Status = EFI_WRITE_PROTECTED;
214 break;
215
216 default:
217 Status = EFI_DEVICE_ERROR;
218 break;
219 }
220
221 if ((Status == EFI_NO_MEDIA) || (Status == EFI_MEDIA_CHANGED)) {
222 WinNtBlockIoReset (&Private->EmuBlockIo, FALSE);
223 }
224
225 return Status;
226 }
227
228 EFI_STATUS
229 WinNtSignalToken (
230 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
231 IN EFI_STATUS Status
232 )
233 {
234 if (Token != NULL) {
235 if (Token->Event != NULL) {
236 // Caller is responcible for signaling EFI Event
237 Token->TransactionStatus = Status;
238 return EFI_SUCCESS;
239 }
240 }
241
242 return Status;
243 }
244
245 /**
246 Read BufferSize bytes from Lba into Buffer.
247
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
252 not be signaled.
253
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
256 replaced.
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.
263
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
268 the read.
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
276 of resources.
277 **/
278 EFI_STATUS
279 WinNtBlockIoReadBlocks (
280 IN EMU_BLOCK_IO_PROTOCOL *This,
281 IN UINT32 MediaId,
282 IN EFI_LBA Lba,
283 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
284 IN UINTN BufferSize,
285 OUT VOID *Buffer
286 )
287 {
288 WIN_NT_BLOCK_IO_PRIVATE *Private;
289 BOOL Flag;
290 EFI_STATUS Status;
291 DWORD BytesRead;
292 UINT64 DistanceToMove;
293 UINT64 DistanceMoved;
294
295 Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
296
297 //
298 // Seek to proper position
299 //
300 DistanceToMove = MultU64x32 (Lba, (UINT32)Private->BlockSize);
301 Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, FILE_BEGIN);
302
303 if (EFI_ERROR (Status) || (DistanceToMove != DistanceMoved)) {
304 DEBUG ((DEBUG_INIT, "ReadBlocks: SetFilePointer failed\n"));
305 return WinNtBlockIoError (Private->Media);
306 }
307
308 Flag = ReadFile (Private->NtHandle, Buffer, (DWORD)BufferSize, (LPDWORD)&BytesRead, NULL);
309 if (!Flag || (BytesRead != BufferSize)) {
310 return WinNtBlockIoError (Private->Media);
311 }
312
313 Private->Media->MediaPresent = TRUE;
314 return WinNtSignalToken (Token, EFI_SUCCESS);
315 }
316
317 /**
318 Write BufferSize bytes from Lba into Buffer.
319
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.
324
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
329 locations.
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.
333
334 @retval EFI_SUCCESS The write request was queued if Event is not NULL.
335 The data was written correctly to the device if
336 the Event is NULL.
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
345 of resources.
346
347 **/
348 EFI_STATUS
349 WinNtBlockIoWriteBlocks (
350 IN EMU_BLOCK_IO_PROTOCOL *This,
351 IN UINT32 MediaId,
352 IN EFI_LBA Lba,
353 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
354 IN UINTN BufferSize,
355 IN VOID *Buffer
356 )
357 {
358 WIN_NT_BLOCK_IO_PRIVATE *Private;
359 UINTN BytesWritten;
360 BOOL Success;
361 EFI_STATUS Status;
362 UINT64 DistanceToMove;
363 UINT64 DistanceMoved;
364
365 Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
366
367 //
368 // Seek to proper position
369 //
370 DistanceToMove = MultU64x32 (Lba, (UINT32)Private->BlockSize);
371 Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, FILE_BEGIN);
372
373 if (EFI_ERROR (Status) || (DistanceToMove != DistanceMoved)) {
374 DEBUG ((DEBUG_INIT, "WriteBlocks: SetFilePointer failed\n"));
375 return WinNtBlockIoError (Private->Media);
376 }
377
378 Success = WriteFile (Private->NtHandle, Buffer, (DWORD)BufferSize, (LPDWORD)&BytesWritten, NULL);
379 if (!Success || (BytesWritten != BufferSize)) {
380 return WinNtBlockIoError (Private->Media);
381 }
382
383 //
384 // If the write succeeded, we are not write protected and media is present.
385 //
386 Private->Media->MediaPresent = TRUE;
387 Private->Media->ReadOnly = FALSE;
388 return WinNtSignalToken (Token, EFI_SUCCESS);
389 }
390
391 /**
392 Flush the Block Device.
393
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.
397
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
400
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
405 the data.
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
410 of resources.
411
412 **/
413 EFI_STATUS
414 WinNtBlockIoFlushBlocks (
415 IN EMU_BLOCK_IO_PROTOCOL *This,
416 IN OUT EFI_BLOCK_IO2_TOKEN *Token
417 )
418 {
419 return WinNtSignalToken (Token, EFI_SUCCESS);
420 }
421
422 /**
423 Reset the block device hardware.
424
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
428 during reset.
429
430 @retval EFI_SUCCESS The device was reset.
431 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
432 not be reset.
433
434 **/
435 EFI_STATUS
436 WinNtBlockIoReset (
437 IN EMU_BLOCK_IO_PROTOCOL *This,
438 IN BOOLEAN ExtendedVerification
439 )
440 {
441 WIN_NT_BLOCK_IO_PRIVATE *Private;
442
443 Private = WIN_NT_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
444
445 if (Private->NtHandle != INVALID_HANDLE_VALUE) {
446 CloseHandle (Private->NtHandle);
447 Private->NtHandle = INVALID_HANDLE_VALUE;
448 }
449
450 return EFI_SUCCESS;
451 }
452
453 EMU_BLOCK_IO_PROTOCOL gEmuBlockIoProtocol = {
454 WinNtBlockIoReset,
455 WinNtBlockIoReadBlocks,
456 WinNtBlockIoWriteBlocks,
457 WinNtBlockIoFlushBlocks,
458 WinNtBlockIoCreateMapping
459 };
460
461 EFI_STATUS
462 EFIAPI
463 WinNtBlockIoThunkOpen (
464 IN EMU_IO_THUNK_PROTOCOL *This
465 )
466 {
467 WIN_NT_BLOCK_IO_PRIVATE *Private;
468 CHAR16 *Str;
469
470 Private = AllocatePool (sizeof (*Private));
471 if (Private == NULL) {
472 return EFI_OUT_OF_RESOURCES;
473 }
474
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;
480
481 Private->FileName = AllocateCopyPool (StrSize (This->ConfigString), This->ConfigString);
482 if (Private->FileName == NULL) {
483 return EFI_OUT_OF_RESOURCES;
484 }
485
486 //
487 // Parse ConfigString
488 // <ConfigString> := <FileName> ':' [RF][OW] ':' <BlockSize>
489 //
490 Str = StrStr (Private->FileName, L":");
491 if (Str == NULL) {
492 Private->Removable = FALSE;
493 Private->Readonly = FALSE;
494 } else {
495 for (*Str++ = L'\0'; *Str != L'\0'; Str++) {
496 if ((*Str == 'R') || (*Str == 'F')) {
497 Private->Removable = (BOOLEAN)(*Str == L'R');
498 }
499
500 if ((*Str == 'O') || (*Str == 'W')) {
501 Private->Readonly = (BOOLEAN)(*Str == L'O');
502 }
503
504 if (*Str == ':') {
505 Private->BlockSize = wcstol (++Str, NULL, 0);
506 break;
507 }
508 }
509 }
510
511 This->Interface = &Private->EmuBlockIo;
512 This->Private = Private;
513 return EFI_SUCCESS;
514 }
515
516 EFI_STATUS
517 EFIAPI
518 WinNtBlockIoThunkClose (
519 IN EMU_IO_THUNK_PROTOCOL *This
520 )
521 {
522 WIN_NT_BLOCK_IO_PRIVATE *Private;
523
524 Private = This->Private;
525
526 if (Private != NULL) {
527 if (Private->FileName != NULL) {
528 FreePool (Private->FileName);
529 }
530
531 FreePool (Private);
532 }
533
534 return EFI_SUCCESS;
535 }
536
537 EMU_IO_THUNK_PROTOCOL mWinNtBlockIoThunkIo = {
538 &gEmuBlockIoProtocolGuid,
539 NULL,
540 NULL,
541 0,
542 WinNtBlockIoThunkOpen,
543 WinNtBlockIoThunkClose,
544 NULL
545 };