2 EFI glue for BIOS INT 13h block devices.
4 This file is coded to EDD 3.0 as defined by T13 D1386 Revision 4
5 Availible on http://www.t13.org/#Project drafts
6 Currently at ftp://fission.dt.wdc.com/pub/standards/x3t13/project/d1386r4.pdf
8 Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>
10 This program and the accompanying materials
11 are licensed and made available under the terms and conditions
12 of the BSD License which accompanies this distribution. The
13 full text of the license may be found at
14 http://opensource.org/licenses/bsd-license.php
16 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
17 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21 #include "BiosBlkIo.h"
24 // Global data declaration
27 // EFI Driver Binding Protocol Instance
29 EFI_DRIVER_BINDING_PROTOCOL gBiosBlockIoDriverBinding
= {
30 BiosBlockIoDriverBindingSupported
,
31 BiosBlockIoDriverBindingStart
,
32 BiosBlockIoDriverBindingStop
,
39 // Semaphore to control access to global variables mActiveInstances and mBufferUnder1Mb
41 EFI_LOCK mGlobalDataLock
= EFI_INITIALIZE_LOCK_VARIABLE(TPL_APPLICATION
);
44 // Number of active instances of this protocol. This is used to allocate/free
45 // the shared buffer. You must acquire the semaphore to modify.
47 UINTN mActiveInstances
= 0;
50 // Pointer to the beginning of the buffer used for real mode thunk
51 // You must acquire the semaphore to modify.
53 EFI_PHYSICAL_ADDRESS mBufferUnder1Mb
= 0;
56 // Address packet is a buffer under 1 MB for all version EDD calls
58 EDD_DEVICE_ADDRESS_PACKET
*mEddBufferUnder1Mb
;
61 // This is a buffer for INT 13h func 48 information
63 BIOS_LEGACY_DRIVE
*mLegacyDriverUnder1Mb
;
66 // Buffer of 0xFE00 bytes for EDD 1.1 transfer must be under 1 MB
67 // 0xFE00 bytes is the max transfer size supported.
74 @param ImageHandle Handle of driver image.
75 @param SystemTable Pointer to system table.
77 @retval EFI_SUCCESS Entrypoint successfully executed.
78 @retval Others Fail to execute entrypoint.
83 BiosBlockIoDriverEntryPoint (
84 IN EFI_HANDLE ImageHandle
,
85 IN EFI_SYSTEM_TABLE
*SystemTable
93 Status
= EfiLibInstallDriverBindingComponentName2 (
96 &gBiosBlockIoDriverBinding
,
98 &gBiosBlockIoComponentName
,
99 &gBiosBlockIoComponentName2
101 if (EFI_ERROR (Status
)) {
105 // Install Legacy BIOS GUID to mark this driver as a BIOS Thunk Driver
107 return gBS
->InstallMultipleProtocolInterfaces (
116 Check whether the driver supports this device.
118 @param This The Udriver binding protocol.
119 @param Controller The controller handle to check.
120 @param RemainingDevicePath The remaining device path.
122 @retval EFI_SUCCESS The driver supports this controller.
123 @retval other This device isn't supported.
128 BiosBlockIoDriverBindingSupported (
129 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
130 IN EFI_HANDLE Controller
,
131 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
135 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
136 EFI_PCI_IO_PROTOCOL
*PciIo
;
137 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
141 // See if the Legacy BIOS Protocol is available
143 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
144 if (EFI_ERROR (Status
)) {
148 Status
= gBS
->OpenProtocol (
150 &gEfiDevicePathProtocolGuid
,
151 (VOID
**) &DevicePath
,
152 This
->DriverBindingHandle
,
154 EFI_OPEN_PROTOCOL_BY_DRIVER
156 if (EFI_ERROR (Status
)) {
162 &gEfiDevicePathProtocolGuid
,
163 This
->DriverBindingHandle
,
168 // Open the IO Abstraction(s) needed to perform the supported test
170 Status
= gBS
->OpenProtocol (
172 &gEfiPciIoProtocolGuid
,
174 This
->DriverBindingHandle
,
176 EFI_OPEN_PROTOCOL_BY_DRIVER
178 if (EFI_ERROR (Status
)) {
182 // See if this is a PCI VGA Controller by looking at the Command register and
183 // Class Code Register
185 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, 0, sizeof (Pci
) / sizeof (UINT32
), &Pci
);
186 if (EFI_ERROR (Status
)) {
187 Status
= EFI_UNSUPPORTED
;
191 Status
= EFI_UNSUPPORTED
;
192 if (Pci
.Hdr
.ClassCode
[2] == PCI_CLASS_MASS_STORAGE
||
193 (Pci
.Hdr
.ClassCode
[2] == PCI_BASE_CLASS_INTELLIGENT
&& Pci
.Hdr
.ClassCode
[1] == PCI_SUB_CLASS_INTELLIGENT
)
195 Status
= EFI_SUCCESS
;
201 &gEfiPciIoProtocolGuid
,
202 This
->DriverBindingHandle
,
210 Starts the device with this driver.
212 @param This The driver binding instance.
213 @param Controller Handle of device to bind driver to.
214 @param RemainingDevicePath Optional parameter use to pick a specific child
217 @retval EFI_SUCCESS The controller is controlled by the driver.
218 @retval Other This controller cannot be started.
223 BiosBlockIoDriverBindingStart (
224 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
225 IN EFI_HANDLE Controller
,
226 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
230 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
231 EFI_PCI_IO_PROTOCOL
*PciIo
;
234 BIOS_BLOCK_IO_DEV
*BiosBlockIoPrivate
;
235 EFI_DEVICE_PATH_PROTOCOL
*PciDevPath
;
239 BOOLEAN DeviceEnable
;
242 // Initialize variables
247 DeviceEnable
= FALSE
;
250 // See if the Legacy BIOS Protocol is available
252 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
253 if (EFI_ERROR (Status
)) {
257 // Open the IO Abstraction(s) needed
259 Status
= gBS
->OpenProtocol (
261 &gEfiPciIoProtocolGuid
,
263 This
->DriverBindingHandle
,
265 EFI_OPEN_PROTOCOL_BY_DRIVER
267 if (EFI_ERROR (Status
)) {
271 Status
= gBS
->OpenProtocol (
273 &gEfiDevicePathProtocolGuid
,
274 (VOID
**) &PciDevPath
,
275 This
->DriverBindingHandle
,
277 EFI_OPEN_PROTOCOL_BY_DRIVER
280 if (EFI_ERROR (Status
)) {
284 // Enable the device and make sure VGA cycles are being forwarded to this VGA device
286 Status
= PciIo
->Attributes (
288 EfiPciIoAttributeOperationEnable
,
289 EFI_PCI_DEVICE_ENABLE
,
292 if (EFI_ERROR (Status
)) {
299 // Check to see if there is a legacy option ROM image associated with this PCI device
301 Status
= LegacyBios
->CheckPciRom (
308 if (EFI_ERROR (Status
)) {
312 // Post the legacy option ROM if it is available.
314 Status
= LegacyBios
->InstallPciRom (
324 if (EFI_ERROR (Status
)) {
328 // All instances share a buffer under 1MB to put real mode thunk code in
329 // If it has not been allocated, then we allocate it.
331 if (mBufferUnder1Mb
== 0) {
333 // Should only be here if there are no active instances
335 ASSERT (mActiveInstances
== 0);
340 EfiAcquireLock (&mGlobalDataLock
);
343 // Allocate below 1MB
345 mBufferUnder1Mb
= 0x00000000000FFFFF;
346 Status
= gBS
->AllocatePages (AllocateMaxAddress
, EfiBootServicesData
, BLOCK_IO_BUFFER_PAGE_SIZE
, &mBufferUnder1Mb
);
351 EfiReleaseLock (&mGlobalDataLock
);
354 // Check memory allocation success
356 if (EFI_ERROR (Status
)) {
358 // In checked builds we want to assert if the allocate failed.
360 ASSERT_EFI_ERROR (Status
);
361 Status
= EFI_OUT_OF_RESOURCES
;
366 TmpAddress
= (UINTN
) mBufferUnder1Mb
;
368 // Adjusting the value to be on proper boundary
370 mEdd11Buffer
= (VOID
*) ALIGN_VARIABLE (TmpAddress
);
372 TmpAddress
= (UINTN
) mEdd11Buffer
+ MAX_EDD11_XFER
;
374 // Adjusting the value to be on proper boundary
376 mLegacyDriverUnder1Mb
= (BIOS_LEGACY_DRIVE
*) ALIGN_VARIABLE (TmpAddress
);
378 TmpAddress
= (UINTN
) mLegacyDriverUnder1Mb
+ sizeof (BIOS_LEGACY_DRIVE
);
380 // Adjusting the value to be on proper boundary
382 mEddBufferUnder1Mb
= (EDD_DEVICE_ADDRESS_PACKET
*) ALIGN_VARIABLE (TmpAddress
);
385 // Allocate the private device structure for each disk
387 for (Index
= DiskStart
; Index
< DiskEnd
; Index
++) {
389 Status
= gBS
->AllocatePool (
391 sizeof (BIOS_BLOCK_IO_DEV
),
392 (VOID
**) &BiosBlockIoPrivate
394 if (EFI_ERROR (Status
)) {
398 // Zero the private device structure
400 ZeroMem (BiosBlockIoPrivate
, sizeof (BIOS_BLOCK_IO_DEV
));
403 // Initialize the private device structure
405 BiosBlockIoPrivate
->Signature
= BIOS_CONSOLE_BLOCK_IO_DEV_SIGNATURE
;
406 BiosBlockIoPrivate
->ControllerHandle
= Controller
;
407 BiosBlockIoPrivate
->LegacyBios
= LegacyBios
;
408 BiosBlockIoPrivate
->PciIo
= PciIo
;
410 BiosBlockIoPrivate
->Bios
.Floppy
= FALSE
;
411 BiosBlockIoPrivate
->Bios
.Number
= (UINT8
) Index
;
412 BiosBlockIoPrivate
->Bios
.Letter
= (UINT8
) (Index
- 0x80 + 'C');
413 BiosBlockIoPrivate
->BlockMedia
.RemovableMedia
= FALSE
;
415 if (BiosInitBlockIo (BiosBlockIoPrivate
)) {
416 SetBiosInitBlockIoDevicePath (PciDevPath
, &BiosBlockIoPrivate
->Bios
, &BiosBlockIoPrivate
->DevicePath
);
419 // Install the Block Io Protocol onto a new child handle
421 Status
= gBS
->InstallMultipleProtocolInterfaces (
422 &BiosBlockIoPrivate
->Handle
,
423 &gEfiBlockIoProtocolGuid
,
424 &BiosBlockIoPrivate
->BlockIo
,
425 &gEfiDevicePathProtocolGuid
,
426 BiosBlockIoPrivate
->DevicePath
,
429 if (EFI_ERROR (Status
)) {
430 gBS
->FreePool (BiosBlockIoPrivate
);
433 // Open For Child Device
435 Status
= gBS
->OpenProtocol (
437 &gEfiPciIoProtocolGuid
,
438 (VOID
**) &BiosBlockIoPrivate
->PciIo
,
439 This
->DriverBindingHandle
,
440 BiosBlockIoPrivate
->Handle
,
441 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
445 gBS
->FreePool (BiosBlockIoPrivate
);
450 if (EFI_ERROR (Status
)) {
455 EfiPciIoAttributeOperationDisable
,
456 EFI_PCI_DEVICE_ENABLE
,
462 &gEfiPciIoProtocolGuid
,
463 This
->DriverBindingHandle
,
466 if (PciDevPath
!= NULL
) {
469 &gEfiDevicePathProtocolGuid
,
470 This
->DriverBindingHandle
,
474 if (mBufferUnder1Mb
!= 0 && mActiveInstances
== 0) {
475 gBS
->FreePages (mBufferUnder1Mb
, BLOCK_IO_BUFFER_PAGE_SIZE
);
478 // Clear the buffer back to 0
480 EfiAcquireLock (&mGlobalDataLock
);
482 EfiReleaseLock (&mGlobalDataLock
);
487 // Successfully installed, so increment the number of active instances
489 EfiAcquireLock (&mGlobalDataLock
);
491 EfiReleaseLock (&mGlobalDataLock
);
498 Stop the device handled by this driver.
500 @param This The driver binding protocol.
501 @param Controller The controller to release.
502 @param NumberOfChildren The number of handles in ChildHandleBuffer.
503 @param ChildHandleBuffer The array of child handle.
505 @retval EFI_SUCCESS The device was stopped.
506 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
507 @retval Others Fail to uninstall protocols attached on the device.
512 BiosBlockIoDriverBindingStop (
513 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
514 IN EFI_HANDLE Controller
,
515 IN UINTN NumberOfChildren
,
516 IN EFI_HANDLE
*ChildHandleBuffer
520 BOOLEAN AllChildrenStopped
;
521 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
522 BIOS_BLOCK_IO_DEV
*BiosBlockIoPrivate
;
526 // Decrement the number of active instances
528 if (mActiveInstances
!= 0) {
530 // Add a check since the stop function will be called 2 times for each handle
532 EfiAcquireLock (&mGlobalDataLock
);
534 EfiReleaseLock (&mGlobalDataLock
);
537 if ((mActiveInstances
== 0) && (mBufferUnder1Mb
!= 0)) {
539 // Free our global buffer
541 Status
= gBS
->FreePages (mBufferUnder1Mb
, BLOCK_IO_BUFFER_PAGE_SIZE
);
542 ASSERT_EFI_ERROR (Status
);
544 EfiAcquireLock (&mGlobalDataLock
);
546 EfiReleaseLock (&mGlobalDataLock
);
549 AllChildrenStopped
= TRUE
;
551 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
552 Status
= gBS
->OpenProtocol (
553 ChildHandleBuffer
[Index
],
554 &gEfiBlockIoProtocolGuid
,
556 This
->DriverBindingHandle
,
558 EFI_OPEN_PROTOCOL_GET_PROTOCOL
560 if (EFI_ERROR (Status
)) {
564 BiosBlockIoPrivate
= BIOS_BLOCK_IO_FROM_THIS (BlockIo
);
567 // Release PCI I/O and Block IO Protocols on the clild handle.
569 Status
= gBS
->UninstallMultipleProtocolInterfaces (
570 ChildHandleBuffer
[Index
],
571 &gEfiBlockIoProtocolGuid
,
572 &BiosBlockIoPrivate
->BlockIo
,
573 &gEfiDevicePathProtocolGuid
,
574 BiosBlockIoPrivate
->DevicePath
,
577 if (EFI_ERROR (Status
)) {
578 AllChildrenStopped
= FALSE
;
581 // Shutdown the hardware
583 BiosBlockIoPrivate
->PciIo
->Attributes (
584 BiosBlockIoPrivate
->PciIo
,
585 EfiPciIoAttributeOperationDisable
,
586 EFI_PCI_DEVICE_ENABLE
,
592 &gEfiPciIoProtocolGuid
,
593 This
->DriverBindingHandle
,
594 ChildHandleBuffer
[Index
]
597 gBS
->FreePool (BiosBlockIoPrivate
);
600 if (!AllChildrenStopped
) {
601 return EFI_DEVICE_ERROR
;
604 Status
= gBS
->CloseProtocol (
606 &gEfiDevicePathProtocolGuid
,
607 This
->DriverBindingHandle
,
611 Status
= gBS
->CloseProtocol (
613 &gEfiPciIoProtocolGuid
,
614 This
->DriverBindingHandle
,
622 Build device path for device.
624 @param BaseDevicePath Base device path.
625 @param Drive Legacy drive.
626 @param DevicePath Device path for output.
630 SetBiosInitBlockIoDevicePath (
631 IN EFI_DEVICE_PATH_PROTOCOL
*BaseDevicePath
,
632 IN BIOS_LEGACY_DRIVE
*Drive
,
633 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
637 BLOCKIO_VENDOR_DEVICE_PATH VendorNode
;
639 Status
= EFI_UNSUPPORTED
;
642 // BugBug: Check for memory leaks!
644 if (Drive
->EddVersion
== EDD_VERSION_30
) {
648 Status
= BuildEdd30DevicePath (BaseDevicePath
, Drive
, DevicePath
);
651 if (EFI_ERROR (Status
)) {
653 // EDD 1.1 device case or it is unrecognized EDD 3.0 device
655 ZeroMem (&VendorNode
, sizeof (VendorNode
));
656 VendorNode
.DevicePath
.Header
.Type
= HARDWARE_DEVICE_PATH
;
657 VendorNode
.DevicePath
.Header
.SubType
= HW_VENDOR_DP
;
658 SetDevicePathNodeLength (&VendorNode
.DevicePath
.Header
, sizeof (VendorNode
));
659 CopyMem (&VendorNode
.DevicePath
.Guid
, &gBlockIoVendorGuid
, sizeof (EFI_GUID
));
660 VendorNode
.LegacyDriveLetter
= Drive
->Number
;
661 *DevicePath
= AppendDevicePathNode (BaseDevicePath
, &VendorNode
.DevicePath
.Header
);
666 Build device path for EDD 3.0.
668 @param BaseDevicePath Base device path.
669 @param Drive Legacy drive.
670 @param DevicePath Device path for output.
672 @retval EFI_SUCCESS The device path is built successfully.
673 @retval EFI_UNSUPPORTED It is failed to built device path.
677 BuildEdd30DevicePath (
678 IN EFI_DEVICE_PATH_PROTOCOL
*BaseDevicePath
,
679 IN BIOS_LEGACY_DRIVE
*Drive
,
680 IN EFI_DEVICE_PATH_PROTOCOL
**DevicePath
684 // AVL UINT64 Address;
685 // AVL EFI_HANDLE Handle;
690 Controller
= (UINT32
) Drive
->Parameters
.InterfacePath
.Pci
.Controller
;
692 ZeroMem (&Node
, sizeof (Node
));
693 if ((AsciiStrnCmp ("ATAPI", Drive
->Parameters
.InterfaceType
, 5) == 0) ||
694 (AsciiStrnCmp ("ATA", Drive
->Parameters
.InterfaceType
, 3) == 0)
697 // ATA or ATAPI drive found
699 Node
.Atapi
.Header
.Type
= MESSAGING_DEVICE_PATH
;
700 Node
.Atapi
.Header
.SubType
= MSG_ATAPI_DP
;
701 SetDevicePathNodeLength (&Node
.Atapi
.Header
, sizeof (ATAPI_DEVICE_PATH
));
702 Node
.Atapi
.SlaveMaster
= Drive
->Parameters
.DevicePath
.Atapi
.Master
;
703 Node
.Atapi
.Lun
= Drive
->Parameters
.DevicePath
.Atapi
.Lun
;
704 Node
.Atapi
.PrimarySecondary
= (UINT8
) Controller
;
707 // Not an ATA/ATAPI drive
709 if (Controller
!= 0) {
710 ZeroMem (&Node
, sizeof (Node
));
711 Node
.Controller
.Header
.Type
= HARDWARE_DEVICE_PATH
;
712 Node
.Controller
.Header
.SubType
= HW_CONTROLLER_DP
;
713 SetDevicePathNodeLength (&Node
.Controller
.Header
, sizeof (CONTROLLER_DEVICE_PATH
));
714 Node
.Controller
.ControllerNumber
= Controller
;
715 *DevicePath
= AppendDevicePathNode (*DevicePath
, &Node
.DevPath
);
718 ZeroMem (&Node
, sizeof (Node
));
720 if (AsciiStrnCmp ("SCSI", Drive
->Parameters
.InterfaceType
, 4) == 0) {
724 Node
.Scsi
.Header
.Type
= MESSAGING_DEVICE_PATH
;
725 Node
.Scsi
.Header
.SubType
= MSG_SCSI_DP
;
726 SetDevicePathNodeLength (&Node
.Scsi
.Header
, sizeof (SCSI_DEVICE_PATH
));
729 // Lun is miss aligned in both EDD and Device Path data structures.
730 // thus we do a byte copy, to prevent alignment traps on IA-64.
732 CopyMem (&Node
.Scsi
.Lun
, &Drive
->Parameters
.DevicePath
.Scsi
.Lun
, sizeof (UINT16
));
733 Node
.Scsi
.Pun
= Drive
->Parameters
.DevicePath
.Scsi
.Pun
;
735 } else if (AsciiStrnCmp ("USB", Drive
->Parameters
.InterfaceType
, 3) == 0) {
739 Node
.Usb
.Header
.Type
= MESSAGING_DEVICE_PATH
;
740 Node
.Usb
.Header
.SubType
= MSG_USB_DP
;
741 SetDevicePathNodeLength (&Node
.Usb
.Header
, sizeof (USB_DEVICE_PATH
));
742 Node
.Usb
.ParentPortNumber
= (UINT8
) Drive
->Parameters
.DevicePath
.Usb
.Reserved
;
744 } else if (AsciiStrnCmp ("1394", Drive
->Parameters
.InterfaceType
, 4) == 0) {
748 Node
.F1394
.Header
.Type
= MESSAGING_DEVICE_PATH
;
749 Node
.F1394
.Header
.SubType
= MSG_1394_DP
;
750 SetDevicePathNodeLength (&Node
.F1394
.Header
, sizeof (F1394_DEVICE_PATH
));
751 Node
.F1394
.Guid
= Drive
->Parameters
.DevicePath
.FireWire
.Guid
;
753 } else if (AsciiStrnCmp ("FIBRE", Drive
->Parameters
.InterfaceType
, 5) == 0) {
757 Node
.FibreChannel
.Header
.Type
= MESSAGING_DEVICE_PATH
;
758 Node
.FibreChannel
.Header
.SubType
= MSG_FIBRECHANNEL_DP
;
759 SetDevicePathNodeLength (&Node
.FibreChannel
.Header
, sizeof (FIBRECHANNEL_DEVICE_PATH
));
760 Node
.FibreChannel
.WWN
= Drive
->Parameters
.DevicePath
.FibreChannel
.Wwn
;
761 Node
.FibreChannel
.Lun
= Drive
->Parameters
.DevicePath
.FibreChannel
.Lun
;
766 DEBUG_BLKIO
, "It is unrecognized EDD 3.0 device, Drive Number = %x, InterfaceType = %s\n",
768 Drive
->Parameters
.InterfaceType
774 if (Node
.DevPath
.Type
== 0) {
775 return EFI_UNSUPPORTED
;
778 *DevicePath
= AppendDevicePathNode (BaseDevicePath
, &Node
.DevPath
);