]> git.proxmox.com Git - mirror_edk2.git/blob - InOsEmuPkg/Unix/Sec/BlockIo.c
61069e3987d1afda88bc43620e991abbca803ab4
[mirror_edk2.git] / InOsEmuPkg / Unix / Sec / BlockIo.c
1 /**@file
2
3 Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 **/
13
14 #include "SecMain.h"
15
16 #define EMU_BLOCK_IO_PRIVATE_SIGNATURE SIGNATURE_32 ('E', 'M', 'b', 'k')
17 typedef struct {
18 UINTN Signature;
19
20 EMU_IO_THUNK_PROTOCOL *Thunk;
21
22 char *Filename;
23 UINTN ReadMode;
24 UINTN Mode;
25
26 int fd;
27
28 BOOLEAN RemovableMedia;
29 BOOLEAN WriteProtected;
30
31 UINT64 NumberOfBlocks;
32
33 EMU_BLOCK_IO_PROTOCOL EmuBlockIo;
34 EFI_BLOCK_IO_MEDIA *Media;
35
36 } EMU_BLOCK_IO_PRIVATE;
37
38 #define EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS(a) \
39 CR(a, EMU_BLOCK_IO_PRIVATE, EmuBlockIo, EMU_BLOCK_IO_PRIVATE_SIGNATURE)
40
41
42
43 EFI_STATUS
44 EmuBlockIoReset (
45 IN EMU_BLOCK_IO_PROTOCOL *This,
46 IN BOOLEAN ExtendedVerification
47 );
48
49
50 /*++
51
52 This function extends the capability of SetFilePointer to accept 64 bit parameters
53
54 **/
55 EFI_STATUS
56 SetFilePointer64 (
57 IN EMU_BLOCK_IO_PRIVATE *Private,
58 IN INT64 DistanceToMove,
59 OUT UINT64 *NewFilePointer,
60 IN INT32 MoveMethod
61 )
62 {
63 EFI_STATUS Status;
64 off_t res;
65 off_t offset = DistanceToMove;
66
67 Status = EFI_SUCCESS;
68 res = lseek (Private->fd, offset, (int)MoveMethod);
69 if (res == -1) {
70 Status = EFI_INVALID_PARAMETER;
71 }
72
73 if (NewFilePointer != NULL) {
74 *NewFilePointer = res;
75 }
76
77 return Status;
78 }
79
80
81 EFI_STATUS
82 EmuBlockIoOpenDevice (
83 IN EMU_BLOCK_IO_PRIVATE *Private
84 )
85 {
86 EFI_STATUS Status;
87 UINT64 FileSize;
88 struct statfs buf;
89
90
91 //
92 // If the device is already opened, close it
93 //
94 if (Private->fd >= 0) {
95 EmuBlockIoReset (&Private->EmuBlockIo, FALSE);
96 }
97
98 //
99 // Open the device
100 //
101 Private->fd = open (Private->Filename, Private->Mode, 0644);
102 if (Private->fd < 0) {
103 printf ("EmuOpenBlock: Could not open %s: %s\n", Private->Filename, strerror(errno));
104 Private->Media->MediaPresent = FALSE;
105 Status = EFI_NO_MEDIA;
106 goto Done;
107 }
108
109 if (!Private->Media->MediaPresent) {
110 //
111 // BugBug: try to emulate if a CD appears - notify drivers to check it out
112 //
113 Private->Media->MediaPresent = TRUE;
114 }
115
116 //
117 // get the size of the file
118 //
119 Status = SetFilePointer64 (Private, 0, &FileSize, SEEK_END);
120 if (EFI_ERROR (Status)) {
121 printf ("EmuOpenBlock: Could not get filesize of %s\n", Private->Filename);
122 Status = EFI_UNSUPPORTED;
123 goto Done;
124 }
125
126 if (FileSize == 0) {
127 // lseek fails on a real device. ioctl calls are OS specific
128 #if __APPLE__
129 {
130 UINT32 BlockSize;
131
132 if (ioctl (Private->fd, DKIOCGETBLOCKSIZE, &BlockSize) == 0) {
133 Private->Media->BlockSize = BlockSize;
134 }
135 if (ioctl (Private->fd, DKIOCGETBLOCKCOUNT, &Private->NumberOfBlocks) == 0) {
136 if ((Private->NumberOfBlocks == 0) && (BlockSize == 0x800)) {
137 // A DVD is ~ 4.37 GB so make up a number
138 Private->Media->LastBlock = (0x100000000ULL/0x800) - 1;
139 } else {
140 Private->Media->LastBlock = Private->NumberOfBlocks - 1;
141 }
142 }
143 ioctl (Private->fd, DKIOCGETMAXBLOCKCOUNTWRITE, &Private->Media->OptimalTransferLengthGranularity);
144 }
145 #else
146 {
147 size_t BlockSize;
148 UINT64 DiskSize;
149
150 if (ioctl (Private->fd, BLKSSZGET, &BlockSize) == 0) {
151 Private->Media->BlockSize = BlockSize;
152 }
153 if (ioctl (Private->fd, BLKGETSIZE64, &DiskSize) == 0) {
154 Private->NumberOfBlocks = DivU64x32 (DiskSize, (UINT32)BlockSize);
155 Private->Media->LastBlock = Private->NumberOfBlocks - 1;
156 }
157 }
158 #endif
159
160 } else if (fstatfs (Private->fd, &buf) == 0) {
161 //
162 // Works for files, not devices
163 //
164 Private->Media->BlockSize = buf.f_bsize;
165 Private->Media->OptimalTransferLengthGranularity = buf.f_iosize/buf.f_bsize;
166 Private->NumberOfBlocks = DivU64x32 (FileSize, Private->Media->BlockSize);
167 Private->Media->LastBlock = Private->NumberOfBlocks - 1;
168 }
169
170 DEBUG ((EFI_D_INIT, "%HEmuOpenBlock: opened %a%N\n", Private->Filename));
171 Status = EFI_SUCCESS;
172
173 Done:
174 if (EFI_ERROR (Status)) {
175 if (Private->fd >= 0) {
176 EmuBlockIoReset (&Private->EmuBlockIo, FALSE);
177 }
178 }
179
180 return Status;
181 }
182
183
184 EFI_STATUS
185 EmuBlockIoCreateMapping (
186 IN EMU_BLOCK_IO_PROTOCOL *This,
187 IN EFI_BLOCK_IO_MEDIA *Media
188 )
189 {
190 EFI_STATUS Status;
191 EMU_BLOCK_IO_PRIVATE *Private;
192
193 Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
194
195 Private->Media = Media;
196
197 Media->MediaId = 0;
198 Media->RemovableMedia = Private->RemovableMedia;
199 Media->MediaPresent = TRUE;
200 Media->LogicalPartition = FALSE;
201 Media->ReadOnly = Private->WriteProtected;
202 Media->WriteCaching = FALSE;
203 Media->IoAlign = 1;
204 Media->LastBlock = 0; // Filled in by OpenDevice
205
206 // EFI_BLOCK_IO_PROTOCOL_REVISION2
207 Media->LowestAlignedLba = 0;
208 Media->LogicalBlocksPerPhysicalBlock = 0;
209
210
211 // EFI_BLOCK_IO_PROTOCOL_REVISION3
212 Media->OptimalTransferLengthGranularity = 0;
213
214 Status = EmuBlockIoOpenDevice (Private);
215
216
217 return Status;
218 }
219
220
221 EFI_STATUS
222 EmuBlockIoError (
223 IN EMU_BLOCK_IO_PRIVATE *Private
224 )
225 {
226 EFI_STATUS Status;
227 BOOLEAN ReinstallBlockIoFlag;
228
229
230 switch (errno) {
231
232 case EAGAIN:
233 Status = EFI_NO_MEDIA;
234 Private->Media->ReadOnly = FALSE;
235 Private->Media->MediaPresent = FALSE;
236 ReinstallBlockIoFlag = FALSE;
237 break;
238
239 case EACCES:
240 Private->Media->ReadOnly = FALSE;
241 Private->Media->MediaPresent = TRUE;
242 Private->Media->MediaId += 1;
243 ReinstallBlockIoFlag = TRUE;
244 Status = EFI_MEDIA_CHANGED;
245 break;
246
247 case EROFS:
248 Private->Media->ReadOnly = TRUE;
249 ReinstallBlockIoFlag = FALSE;
250 Status = EFI_WRITE_PROTECTED;
251 break;
252
253 default:
254 ReinstallBlockIoFlag = FALSE;
255 Status = EFI_DEVICE_ERROR;
256 break;
257 }
258 /*
259 if (ReinstallBlockIoFlag) {
260 Private->EmuBlockIo->Reset (&Private->EmuBlockIo, FALSE);
261
262 gBS->ReinstallProtocolInterface (
263 Private->EfiHandle,
264 &gEfiBlockIoProtocolGuid,
265 BlockIo,
266 BlockIo
267 );
268 }
269 */
270 return Status;
271 }
272
273 EFI_STATUS
274 EmuBlockIoReadWriteCommon (
275 IN EMU_BLOCK_IO_PRIVATE *Private,
276 IN UINT32 MediaId,
277 IN EFI_LBA Lba,
278 IN UINTN BufferSize,
279 IN VOID *Buffer,
280 IN CHAR8 *CallerName
281 )
282 {
283 EFI_STATUS Status;
284 UINTN BlockSize;
285 UINT64 LastBlock;
286 INT64 DistanceToMove;
287 UINT64 DistanceMoved;
288
289 if (Private->fd < 0) {
290 Status = EmuBlockIoOpenDevice (Private);
291 if (EFI_ERROR (Status)) {
292 return Status;
293 }
294 }
295
296 if (!Private->Media->MediaPresent) {
297 DEBUG ((EFI_D_INIT, "%s: No Media\n", CallerName));
298 return EFI_NO_MEDIA;
299 }
300
301 if (Private->Media->MediaId != MediaId) {
302 return EFI_MEDIA_CHANGED;
303 }
304
305 if ((UINTN) Buffer % Private->Media->IoAlign != 0) {
306 return EFI_INVALID_PARAMETER;
307 }
308
309 //
310 // Verify buffer size
311 //
312 BlockSize = Private->Media->BlockSize;
313 if (BufferSize == 0) {
314 DEBUG ((EFI_D_INIT, "%s: Zero length read\n", CallerName));
315 return EFI_SUCCESS;
316 }
317
318 if ((BufferSize % BlockSize) != 0) {
319 DEBUG ((EFI_D_INIT, "%s: Invalid read size\n", CallerName));
320 return EFI_BAD_BUFFER_SIZE;
321 }
322
323 LastBlock = Lba + (BufferSize / BlockSize) - 1;
324 if (LastBlock > Private->Media->LastBlock) {
325 DEBUG ((EFI_D_INIT, "ReadBlocks: Attempted to read off end of device\n"));
326 return EFI_INVALID_PARAMETER;
327 }
328 //
329 // Seek to End of File
330 //
331 DistanceToMove = MultU64x32 (Lba, BlockSize);
332 Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, SEEK_SET);
333
334 if (EFI_ERROR (Status)) {
335 DEBUG ((EFI_D_INIT, "WriteBlocks: SetFilePointer failed\n"));
336 return EmuBlockIoError (Private);
337 }
338
339 return EFI_SUCCESS;
340 }
341
342
343 /**
344 Read BufferSize bytes from Lba into Buffer.
345
346 This function reads the requested number of blocks from the device. All the
347 blocks are read, or an error is returned.
348 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
349 non-blocking I/O is being used, the Event associated with this request will
350 not be signaled.
351
352 @param[in] This Indicates a pointer to the calling context.
353 @param[in] MediaId Id of the media, changes every time the media is
354 replaced.
355 @param[in] Lba The starting Logical Block Address to read from.
356 @param[in, out] Token A pointer to the token associated with the transaction.
357 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
358 @param[out] Buffer A pointer to the destination buffer for the data. The
359 caller is responsible for either having implicit or
360 explicit ownership of the buffer.
361
362 @retval EFI_SUCCESS The read request was queued if Token->Event is
363 not NULL.The data was read correctly from the
364 device if the Token->Event is NULL.
365 @retval EFI_DEVICE_ERROR The device reported an error while performing
366 the read.
367 @retval EFI_NO_MEDIA There is no media in the device.
368 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
369 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
370 intrinsic block size of the device.
371 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
372 or the buffer is not on proper alignment.
373 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
374 of resources.
375 **/
376 EFI_STATUS
377 EmuBlockIoReadBlocks (
378 IN EMU_BLOCK_IO_PROTOCOL *This,
379 IN UINT32 MediaId,
380 IN EFI_LBA LBA,
381 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
382 IN UINTN BufferSize,
383 OUT VOID *Buffer
384 )
385 {
386 EFI_STATUS Status;
387 EMU_BLOCK_IO_PRIVATE *Private;
388 ssize_t len;
389
390 Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
391
392 Status = EmuBlockIoReadWriteCommon (Private, MediaId, LBA, BufferSize, Buffer, "UnixReadBlocks");
393 if (EFI_ERROR (Status)) {
394 goto Done;
395 }
396
397 len = read (Private->fd, Buffer, BufferSize);
398 if (len != BufferSize) {
399 DEBUG ((EFI_D_INIT, "ReadBlocks: ReadFile failed.\n"));
400 Status = EmuBlockIoError (Private);
401 goto Done;
402 }
403
404 //
405 // If we read then media is present.
406 //
407 Private->Media->MediaPresent = TRUE;
408 Status = EFI_SUCCESS;
409
410 Done:
411 if (Token != NULL) {
412 if (Token->Event != NULL) {
413 // Caller is responcible for signaling EFI Event
414 Token->TransactionStatus = Status;
415 return EFI_SUCCESS;
416 }
417 }
418 return Status;
419 }
420
421
422 /**
423 Write BufferSize bytes from Lba into Buffer.
424
425 This function writes the requested number of blocks to the device. All blocks
426 are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
427 EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
428 being used, the Event associated with this request will not be signaled.
429
430 @param[in] This Indicates a pointer to the calling context.
431 @param[in] MediaId The media ID that the write request is for.
432 @param[in] Lba The starting logical block address to be written. The
433 caller is responsible for writing to only legitimate
434 locations.
435 @param[in, out] Token A pointer to the token associated with the transaction.
436 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
437 @param[in] Buffer A pointer to the source buffer for the data.
438
439 @retval EFI_SUCCESS The write request was queued if Event is not NULL.
440 The data was written correctly to the device if
441 the Event is NULL.
442 @retval EFI_WRITE_PROTECTED The device can not be written to.
443 @retval EFI_NO_MEDIA There is no media in the device.
444 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
445 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
446 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
447 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
448 or the buffer is not on proper alignment.
449 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
450 of resources.
451
452 **/
453 EFI_STATUS
454 EmuBlockIoWriteBlocks (
455 IN EMU_BLOCK_IO_PROTOCOL *This,
456 IN UINT32 MediaId,
457 IN EFI_LBA LBA,
458 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
459 IN UINTN BufferSize,
460 IN VOID *Buffer
461 )
462 {
463 EMU_BLOCK_IO_PRIVATE *Private;
464 ssize_t len;
465 EFI_STATUS Status;
466
467
468 Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
469
470 Status = EmuBlockIoReadWriteCommon (Private, MediaId, LBA, BufferSize, Buffer, "UnixWriteBlocks");
471 if (EFI_ERROR (Status)) {
472 goto Done;
473 }
474
475 len = write (Private->fd, Buffer, BufferSize);
476 if (len != BufferSize) {
477 DEBUG ((EFI_D_INIT, "ReadBlocks: WriteFile failed.\n"));
478 Status = EmuBlockIoError (Private);
479 goto Done;
480 }
481
482 //
483 // If the write succeeded, we are not write protected and media is present.
484 //
485 Private->Media->MediaPresent = TRUE;
486 Private->Media->ReadOnly = FALSE;
487 Status = EFI_SUCCESS;
488
489 Done:
490 if (Token != NULL) {
491 if (Token->Event != NULL) {
492 // Caller is responcible for signaling EFI Event
493 Token->TransactionStatus = Status;
494 return EFI_SUCCESS;
495 }
496 }
497
498 return Status;
499 }
500
501
502 /**
503 Flush the Block Device.
504
505 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
506 is returned and non-blocking I/O is being used, the Event associated with
507 this request will not be signaled.
508
509 @param[in] This Indicates a pointer to the calling context.
510 @param[in,out] Token A pointer to the token associated with the transaction
511
512 @retval EFI_SUCCESS The flush request was queued if Event is not NULL.
513 All outstanding data was written correctly to the
514 device if the Event is NULL.
515 @retval EFI_DEVICE_ERROR The device reported an error while writting back
516 the data.
517 @retval EFI_WRITE_PROTECTED The device cannot be written to.
518 @retval EFI_NO_MEDIA There is no media in the device.
519 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
520 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
521 of resources.
522
523 **/
524 EFI_STATUS
525 EmuBlockIoFlushBlocks (
526 IN EMU_BLOCK_IO_PROTOCOL *This,
527 IN OUT EFI_BLOCK_IO2_TOKEN *Token
528 )
529 {
530 EMU_BLOCK_IO_PRIVATE *Private;
531 int Res;
532
533 Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
534
535 if (Private->fd >= 0) {
536 Res = fcntl (Private->fd, F_FULLFSYNC);
537 }
538
539
540 if (Token != NULL) {
541 if (Token->Event != NULL) {
542 // Caller is responcible for signaling EFI Event
543 Token->TransactionStatus = EFI_SUCCESS;
544 return EFI_SUCCESS;
545 }
546 }
547
548 return EFI_SUCCESS;
549 }
550
551
552 /**
553 Reset the block device hardware.
554
555 @param[in] This Indicates a pointer to the calling context.
556 @param[in] ExtendedVerification Indicates that the driver may perform a more
557 exhausive verfication operation of the device
558 during reset.
559
560 @retval EFI_SUCCESS The device was reset.
561 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
562 not be reset.
563
564 **/
565 EFI_STATUS
566 EmuBlockIoReset (
567 IN EMU_BLOCK_IO_PROTOCOL *This,
568 IN BOOLEAN ExtendedVerification
569 )
570 /*++
571
572 Routine Description:
573 Reset the Block Device.
574
575 Arguments:
576 This - Protocol instance pointer.
577 ExtendedVerification - Driver may perform diagnostics on reset.
578
579 Returns:
580 EFI_SUCCESS - The device was reset.
581 EFI_DEVICE_ERROR - The device is not functioning properly and could
582 not be reset.
583
584 **/
585 {
586 EMU_BLOCK_IO_PRIVATE *Private;
587
588 Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);
589
590 if (Private->fd >= 0) {
591 close (Private->fd);
592 Private->fd = -1;
593 }
594
595 return EFI_SUCCESS;
596 }
597
598
599 char *
600 StdDupUnicodeToAscii (
601 IN CHAR16 *Str
602 )
603 {
604 UINTN Size;
605 char *Ascii;
606 char *Ptr;
607
608 Size = StrLen (Str) + 1;
609 Ascii = malloc (Size);
610 if (Ascii == NULL) {
611 return NULL;
612 }
613
614 for (Ptr = Ascii; *Str != '\0'; Ptr++, Str++) {
615 *Ptr = *Str;
616 }
617 *Ptr = 0;
618
619 return Ascii;
620 }
621
622
623 EMU_BLOCK_IO_PROTOCOL gEmuBlockIoProtocol = {
624 GasketEmuBlockIoReset,
625 GasketEmuBlockIoReadBlocks,
626 GasketEmuBlockIoWriteBlocks,
627 GasketEmuBlockIoFlushBlocks,
628 GasketEmuBlockIoCreateMapping
629 };
630
631 EFI_STATUS
632 EmuBlockIoThunkOpen (
633 IN EMU_IO_THUNK_PROTOCOL *This
634 )
635 {
636 EMU_BLOCK_IO_PRIVATE *Private;
637 char *Str;
638
639 if (This->Private != NULL) {
640 return EFI_ALREADY_STARTED;
641 }
642
643 if (!CompareGuid (This->Protocol, &gEmuBlockIoProtocolGuid)) {
644 return EFI_UNSUPPORTED;
645 }
646
647 Private = malloc (sizeof (EMU_BLOCK_IO_PRIVATE));
648 if (Private == NULL) {
649 return EFI_OUT_OF_RESOURCES;
650 }
651
652
653 Private->Signature = EMU_BLOCK_IO_PRIVATE_SIGNATURE;
654 Private->Thunk = This;
655 CopyMem (&Private->EmuBlockIo, &gEmuBlockIoProtocol, sizeof (gEmuBlockIoProtocol));
656 Private->fd = -1;
657
658 Private->Filename = StdDupUnicodeToAscii (This->ConfigString);
659 if (Private->Filename == NULL) {
660 return EFI_OUT_OF_RESOURCES;
661 }
662
663 Str = strstr (Private->Filename, ":");
664 if (Str == NULL) {
665 Private->RemovableMedia = FALSE;
666 Private->WriteProtected = FALSE;
667 } else {
668 for (*Str++ = '\0'; *Str != 0; Str++) {
669 if (*Str == 'R' || *Str == 'F') {
670 Private->RemovableMedia = (BOOLEAN) (*Str == 'R');
671 }
672 if (*Str == 'O' || *Str == 'W') {
673 Private->WriteProtected = (BOOLEAN) (*Str == 'O');
674 }
675 }
676 }
677
678 This->Interface = &Private->EmuBlockIo;
679 This->Private = Private;
680 return EFI_SUCCESS;
681 }
682
683
684 EFI_STATUS
685 EmuBlockIoThunkClose (
686 IN EMU_IO_THUNK_PROTOCOL *This
687 )
688 {
689 EMU_BLOCK_IO_PRIVATE *Private;
690
691 if (!CompareGuid (This->Protocol, &gEmuBlockIoProtocolGuid)) {
692 return EFI_UNSUPPORTED;
693 }
694
695 Private = This->Private;
696
697 if (This->Private != NULL) {
698 if (Private->Filename != NULL) {
699 free (Private->Filename);
700 }
701 free (This->Private);
702 This->Private = NULL;
703 }
704
705 return EFI_SUCCESS;
706 }
707
708
709
710 EMU_IO_THUNK_PROTOCOL gBlockIoThunkIo = {
711 &gEmuBlockIoProtocolGuid,
712 NULL,
713 NULL,
714 0,
715 GasketBlockIoThunkOpen,
716 GasketBlockIoThunkClose,
717 NULL
718 };
719
720