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 - 2010, 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.
71 EFI_GUID mUnknownDevGuid
= UNKNOWN_DEVICE_GUID
;
76 @param ImageHandle Handle of driver image.
77 @param SystemTable Pointer to system table.
79 @retval EFI_SUCCESS Entrypoint successfully executed.
80 @retval Others Fail to execute entrypoint.
85 BiosBlockIoDriverEntryPoint (
86 IN EFI_HANDLE ImageHandle
,
87 IN EFI_SYSTEM_TABLE
*SystemTable
95 Status
= EfiLibInstallDriverBindingComponentName2 (
98 &gBiosBlockIoDriverBinding
,
100 &gBiosBlockIoComponentName
,
101 &gBiosBlockIoComponentName2
103 if (EFI_ERROR (Status
)) {
107 // Install Legacy BIOS GUID to mark this driver as a BIOS Thunk Driver
109 return gBS
->InstallMultipleProtocolInterfaces (
118 Check whether the driver supports this device.
120 @param This The Udriver binding protocol.
121 @param Controller The controller handle to check.
122 @param RemainingDevicePath The remaining device path.
124 @retval EFI_SUCCESS The driver supports this controller.
125 @retval other This device isn't supported.
130 BiosBlockIoDriverBindingSupported (
131 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
132 IN EFI_HANDLE Controller
,
133 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
137 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
138 EFI_PCI_IO_PROTOCOL
*PciIo
;
139 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
143 // See if the Legacy BIOS Protocol is available
145 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
146 if (EFI_ERROR (Status
)) {
150 Status
= gBS
->OpenProtocol (
152 &gEfiDevicePathProtocolGuid
,
153 (VOID
**) &DevicePath
,
154 This
->DriverBindingHandle
,
156 EFI_OPEN_PROTOCOL_BY_DRIVER
158 if (EFI_ERROR (Status
)) {
164 &gEfiDevicePathProtocolGuid
,
165 This
->DriverBindingHandle
,
170 // Open the IO Abstraction(s) needed to perform the supported test
172 Status
= gBS
->OpenProtocol (
174 &gEfiPciIoProtocolGuid
,
176 This
->DriverBindingHandle
,
178 EFI_OPEN_PROTOCOL_BY_DRIVER
180 if (EFI_ERROR (Status
)) {
184 // See if this is a PCI VGA Controller by looking at the Command register and
185 // Class Code Register
187 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, 0, sizeof (Pci
) / sizeof (UINT32
), &Pci
);
188 if (EFI_ERROR (Status
)) {
189 Status
= EFI_UNSUPPORTED
;
193 Status
= EFI_UNSUPPORTED
;
194 if (Pci
.Hdr
.ClassCode
[2] == PCI_CLASS_MASS_STORAGE
||
195 (Pci
.Hdr
.ClassCode
[2] == PCI_BASE_CLASS_INTELLIGENT
&& Pci
.Hdr
.ClassCode
[1] == PCI_SUB_CLASS_INTELLIGENT
)
197 Status
= EFI_SUCCESS
;
203 &gEfiPciIoProtocolGuid
,
204 This
->DriverBindingHandle
,
212 Starts the device with this driver.
214 @param This The driver binding instance.
215 @param Controller Handle of device to bind driver to.
216 @param RemainingDevicePath Optional parameter use to pick a specific child
219 @retval EFI_SUCCESS The controller is controlled by the driver.
220 @retval Other This controller cannot be started.
225 BiosBlockIoDriverBindingStart (
226 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
227 IN EFI_HANDLE Controller
,
228 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
232 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
233 EFI_PCI_IO_PROTOCOL
*PciIo
;
236 BIOS_BLOCK_IO_DEV
*BiosBlockIoPrivate
;
237 EFI_DEVICE_PATH_PROTOCOL
*PciDevPath
;
241 BOOLEAN DeviceEnable
;
244 // Initialize variables
249 DeviceEnable
= FALSE
;
252 // See if the Legacy BIOS Protocol is available
254 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
255 if (EFI_ERROR (Status
)) {
259 // Open the IO Abstraction(s) needed
261 Status
= gBS
->OpenProtocol (
263 &gEfiPciIoProtocolGuid
,
265 This
->DriverBindingHandle
,
267 EFI_OPEN_PROTOCOL_BY_DRIVER
269 if (EFI_ERROR (Status
)) {
273 Status
= gBS
->OpenProtocol (
275 &gEfiDevicePathProtocolGuid
,
276 (VOID
**) &PciDevPath
,
277 This
->DriverBindingHandle
,
279 EFI_OPEN_PROTOCOL_BY_DRIVER
282 if (EFI_ERROR (Status
)) {
286 // Enable the device and make sure VGA cycles are being forwarded to this VGA device
288 Status
= PciIo
->Attributes (
290 EfiPciIoAttributeOperationEnable
,
291 EFI_PCI_DEVICE_ENABLE
,
294 if (EFI_ERROR (Status
)) {
301 // Check to see if there is a legacy option ROM image associated with this PCI device
303 Status
= LegacyBios
->CheckPciRom (
310 if (EFI_ERROR (Status
)) {
314 // Post the legacy option ROM if it is available.
316 Status
= LegacyBios
->InstallPciRom (
326 if (EFI_ERROR (Status
)) {
330 // All instances share a buffer under 1MB to put real mode thunk code in
331 // If it has not been allocated, then we allocate it.
333 if (mBufferUnder1Mb
== 0) {
335 // Should only be here if there are no active instances
337 ASSERT (mActiveInstances
== 0);
342 EfiAcquireLock (&mGlobalDataLock
);
345 // Allocate below 1MB
347 mBufferUnder1Mb
= 0x00000000000FFFFF;
348 Status
= gBS
->AllocatePages (AllocateMaxAddress
, EfiBootServicesData
, BLOCK_IO_BUFFER_PAGE_SIZE
, &mBufferUnder1Mb
);
353 EfiReleaseLock (&mGlobalDataLock
);
356 // Check memory allocation success
358 if (EFI_ERROR (Status
)) {
360 // In checked builds we want to assert if the allocate failed.
362 ASSERT_EFI_ERROR (Status
);
363 Status
= EFI_OUT_OF_RESOURCES
;
368 TmpAddress
= (UINTN
) mBufferUnder1Mb
;
370 // Adjusting the value to be on proper boundary
372 mEdd11Buffer
= (VOID
*) ALIGN_VARIABLE (TmpAddress
);
374 TmpAddress
= (UINTN
) mEdd11Buffer
+ MAX_EDD11_XFER
;
376 // Adjusting the value to be on proper boundary
378 mLegacyDriverUnder1Mb
= (BIOS_LEGACY_DRIVE
*) ALIGN_VARIABLE (TmpAddress
);
380 TmpAddress
= (UINTN
) mLegacyDriverUnder1Mb
+ sizeof (BIOS_LEGACY_DRIVE
);
382 // Adjusting the value to be on proper boundary
384 mEddBufferUnder1Mb
= (EDD_DEVICE_ADDRESS_PACKET
*) ALIGN_VARIABLE (TmpAddress
);
387 // Allocate the private device structure for each disk
389 for (Index
= DiskStart
; Index
< DiskEnd
; Index
++) {
391 Status
= gBS
->AllocatePool (
393 sizeof (BIOS_BLOCK_IO_DEV
),
394 (VOID
**) &BiosBlockIoPrivate
396 if (EFI_ERROR (Status
)) {
400 // Zero the private device structure
402 ZeroMem (BiosBlockIoPrivate
, sizeof (BIOS_BLOCK_IO_DEV
));
405 // Initialize the private device structure
407 BiosBlockIoPrivate
->Signature
= BIOS_CONSOLE_BLOCK_IO_DEV_SIGNATURE
;
408 BiosBlockIoPrivate
->ControllerHandle
= Controller
;
409 BiosBlockIoPrivate
->LegacyBios
= LegacyBios
;
410 BiosBlockIoPrivate
->PciIo
= PciIo
;
412 BiosBlockIoPrivate
->Bios
.Floppy
= FALSE
;
413 BiosBlockIoPrivate
->Bios
.Number
= (UINT8
) Index
;
414 BiosBlockIoPrivate
->Bios
.Letter
= (UINT8
) (Index
- 0x80 + 'C');
415 BiosBlockIoPrivate
->BlockMedia
.RemovableMedia
= FALSE
;
417 if (BiosInitBlockIo (BiosBlockIoPrivate
)) {
418 SetBiosInitBlockIoDevicePath (PciDevPath
, &BiosBlockIoPrivate
->Bios
, &BiosBlockIoPrivate
->DevicePath
);
421 // Install the Block Io Protocol onto a new child handle
423 Status
= gBS
->InstallMultipleProtocolInterfaces (
424 &BiosBlockIoPrivate
->Handle
,
425 &gEfiBlockIoProtocolGuid
,
426 &BiosBlockIoPrivate
->BlockIo
,
427 &gEfiDevicePathProtocolGuid
,
428 BiosBlockIoPrivate
->DevicePath
,
431 if (EFI_ERROR (Status
)) {
432 gBS
->FreePool (BiosBlockIoPrivate
);
435 // Open For Child Device
437 Status
= gBS
->OpenProtocol (
439 &gEfiPciIoProtocolGuid
,
440 (VOID
**) &BiosBlockIoPrivate
->PciIo
,
441 This
->DriverBindingHandle
,
442 BiosBlockIoPrivate
->Handle
,
443 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
447 gBS
->FreePool (BiosBlockIoPrivate
);
452 if (EFI_ERROR (Status
)) {
457 EfiPciIoAttributeOperationDisable
,
458 EFI_PCI_DEVICE_ENABLE
,
464 &gEfiPciIoProtocolGuid
,
465 This
->DriverBindingHandle
,
468 if (PciDevPath
!= NULL
) {
471 &gEfiDevicePathProtocolGuid
,
472 This
->DriverBindingHandle
,
476 if (mBufferUnder1Mb
!= 0 && mActiveInstances
== 0) {
477 gBS
->FreePages (mBufferUnder1Mb
, BLOCK_IO_BUFFER_PAGE_SIZE
);
480 // Clear the buffer back to 0
482 EfiAcquireLock (&mGlobalDataLock
);
484 EfiReleaseLock (&mGlobalDataLock
);
489 // Successfully installed, so increment the number of active instances
491 EfiAcquireLock (&mGlobalDataLock
);
493 EfiReleaseLock (&mGlobalDataLock
);
500 Stop the device handled by this driver.
502 @param This The driver binding protocol.
503 @param Controller The controller to release.
504 @param NumberOfChildren The number of handles in ChildHandleBuffer.
505 @param ChildHandleBuffer The array of child handle.
507 @retval EFI_SUCCESS The device was stopped.
508 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
509 @retval Others Fail to uninstall protocols attached on the device.
514 BiosBlockIoDriverBindingStop (
515 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
516 IN EFI_HANDLE Controller
,
517 IN UINTN NumberOfChildren
,
518 IN EFI_HANDLE
*ChildHandleBuffer
522 BOOLEAN AllChildrenStopped
;
523 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
524 BIOS_BLOCK_IO_DEV
*BiosBlockIoPrivate
;
528 // Decrement the number of active instances
530 if (mActiveInstances
!= 0) {
532 // Add a check since the stop function will be called 2 times for each handle
534 EfiAcquireLock (&mGlobalDataLock
);
536 EfiReleaseLock (&mGlobalDataLock
);
539 if ((mActiveInstances
== 0) && (mBufferUnder1Mb
!= 0)) {
541 // Free our global buffer
543 Status
= gBS
->FreePages (mBufferUnder1Mb
, BLOCK_IO_BUFFER_PAGE_SIZE
);
544 ASSERT_EFI_ERROR (Status
);
546 EfiAcquireLock (&mGlobalDataLock
);
548 EfiReleaseLock (&mGlobalDataLock
);
551 AllChildrenStopped
= TRUE
;
553 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
554 Status
= gBS
->OpenProtocol (
555 ChildHandleBuffer
[Index
],
556 &gEfiBlockIoProtocolGuid
,
558 This
->DriverBindingHandle
,
560 EFI_OPEN_PROTOCOL_GET_PROTOCOL
562 if (EFI_ERROR (Status
)) {
566 BiosBlockIoPrivate
= BIOS_BLOCK_IO_FROM_THIS (BlockIo
);
569 // Release PCI I/O and Block IO Protocols on the clild handle.
571 Status
= gBS
->UninstallMultipleProtocolInterfaces (
572 ChildHandleBuffer
[Index
],
573 &gEfiBlockIoProtocolGuid
,
574 &BiosBlockIoPrivate
->BlockIo
,
575 &gEfiDevicePathProtocolGuid
,
576 BiosBlockIoPrivate
->DevicePath
,
579 if (EFI_ERROR (Status
)) {
580 AllChildrenStopped
= FALSE
;
583 // Shutdown the hardware
585 BiosBlockIoPrivate
->PciIo
->Attributes (
586 BiosBlockIoPrivate
->PciIo
,
587 EfiPciIoAttributeOperationDisable
,
588 EFI_PCI_DEVICE_ENABLE
,
594 &gEfiPciIoProtocolGuid
,
595 This
->DriverBindingHandle
,
596 ChildHandleBuffer
[Index
]
599 gBS
->FreePool (BiosBlockIoPrivate
);
602 if (!AllChildrenStopped
) {
603 return EFI_DEVICE_ERROR
;
606 Status
= gBS
->CloseProtocol (
608 &gEfiDevicePathProtocolGuid
,
609 This
->DriverBindingHandle
,
613 Status
= gBS
->CloseProtocol (
615 &gEfiPciIoProtocolGuid
,
616 This
->DriverBindingHandle
,
624 Build device path for device.
626 @param BaseDevicePath Base device path.
627 @param Drive Legacy drive.
628 @param DevicePath Device path for output.
632 SetBiosInitBlockIoDevicePath (
633 IN EFI_DEVICE_PATH_PROTOCOL
*BaseDevicePath
,
634 IN BIOS_LEGACY_DRIVE
*Drive
,
635 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
639 UNKNOWN_DEVICE_VENDOR_DEVICE_PATH VendorNode
;
641 Status
= EFI_UNSUPPORTED
;
644 // BugBug: Check for memory leaks!
646 if (Drive
->EddVersion
== EDD_VERSION_30
) {
650 Status
= BuildEdd30DevicePath (BaseDevicePath
, Drive
, DevicePath
);
653 if (EFI_ERROR (Status
)) {
655 // EDD 1.1 device case or it is unrecognized EDD 3.0 device
657 ZeroMem (&VendorNode
, sizeof (VendorNode
));
658 VendorNode
.DevicePath
.Header
.Type
= HARDWARE_DEVICE_PATH
;
659 VendorNode
.DevicePath
.Header
.SubType
= HW_VENDOR_DP
;
660 SetDevicePathNodeLength (&VendorNode
.DevicePath
.Header
, sizeof (VendorNode
));
661 CopyMem (&VendorNode
.DevicePath
.Guid
, &mUnknownDevGuid
, sizeof (EFI_GUID
));
662 VendorNode
.LegacyDriveLetter
= Drive
->Number
;
663 *DevicePath
= AppendDevicePathNode (BaseDevicePath
, &VendorNode
.DevicePath
.Header
);
668 Build device path for EDD 3.0.
670 @param BaseDevicePath Base device path.
671 @param Drive Legacy drive.
672 @param DevicePath Device path for output.
674 @retval EFI_SUCCESS The device path is built successfully.
675 @retval EFI_UNSUPPORTED It is failed to built device path.
679 BuildEdd30DevicePath (
680 IN EFI_DEVICE_PATH_PROTOCOL
*BaseDevicePath
,
681 IN BIOS_LEGACY_DRIVE
*Drive
,
682 IN EFI_DEVICE_PATH_PROTOCOL
**DevicePath
686 // AVL UINT64 Address;
687 // AVL EFI_HANDLE Handle;
692 Controller
= (UINT32
) Drive
->Parameters
.InterfacePath
.Pci
.Controller
;
694 ZeroMem (&Node
, sizeof (Node
));
695 if ((AsciiStrnCmp ("ATAPI", Drive
->Parameters
.InterfaceType
, 5) == 0) ||
696 (AsciiStrnCmp ("ATA", Drive
->Parameters
.InterfaceType
, 3) == 0)
699 // ATA or ATAPI drive found
701 Node
.Atapi
.Header
.Type
= MESSAGING_DEVICE_PATH
;
702 Node
.Atapi
.Header
.SubType
= MSG_ATAPI_DP
;
703 SetDevicePathNodeLength (&Node
.Atapi
.Header
, sizeof (ATAPI_DEVICE_PATH
));
704 Node
.Atapi
.SlaveMaster
= Drive
->Parameters
.DevicePath
.Atapi
.Master
;
705 Node
.Atapi
.Lun
= Drive
->Parameters
.DevicePath
.Atapi
.Lun
;
706 Node
.Atapi
.PrimarySecondary
= (UINT8
) Controller
;
709 // Not an ATA/ATAPI drive
711 if (Controller
!= 0) {
712 ZeroMem (&Node
, sizeof (Node
));
713 Node
.Controller
.Header
.Type
= HARDWARE_DEVICE_PATH
;
714 Node
.Controller
.Header
.SubType
= HW_CONTROLLER_DP
;
715 SetDevicePathNodeLength (&Node
.Controller
.Header
, sizeof (CONTROLLER_DEVICE_PATH
));
716 Node
.Controller
.ControllerNumber
= Controller
;
717 *DevicePath
= AppendDevicePathNode (*DevicePath
, &Node
.DevPath
);
720 ZeroMem (&Node
, sizeof (Node
));
722 if (AsciiStrnCmp ("SCSI", Drive
->Parameters
.InterfaceType
, 4) == 0) {
726 Node
.Scsi
.Header
.Type
= MESSAGING_DEVICE_PATH
;
727 Node
.Scsi
.Header
.SubType
= MSG_SCSI_DP
;
728 SetDevicePathNodeLength (&Node
.Scsi
.Header
, sizeof (SCSI_DEVICE_PATH
));
731 // Lun is miss aligned in both EDD and Device Path data structures.
732 // thus we do a byte copy, to prevent alignment traps on IA-64.
734 CopyMem (&Node
.Scsi
.Lun
, &Drive
->Parameters
.DevicePath
.Scsi
.Lun
, sizeof (UINT16
));
735 Node
.Scsi
.Pun
= Drive
->Parameters
.DevicePath
.Scsi
.Pun
;
737 } else if (AsciiStrnCmp ("USB", Drive
->Parameters
.InterfaceType
, 3) == 0) {
741 Node
.Usb
.Header
.Type
= MESSAGING_DEVICE_PATH
;
742 Node
.Usb
.Header
.SubType
= MSG_USB_DP
;
743 SetDevicePathNodeLength (&Node
.Usb
.Header
, sizeof (USB_DEVICE_PATH
));
744 Node
.Usb
.ParentPortNumber
= (UINT8
) Drive
->Parameters
.DevicePath
.Usb
.Reserved
;
746 } else if (AsciiStrnCmp ("1394", Drive
->Parameters
.InterfaceType
, 4) == 0) {
750 Node
.F1394
.Header
.Type
= MESSAGING_DEVICE_PATH
;
751 Node
.F1394
.Header
.SubType
= MSG_1394_DP
;
752 SetDevicePathNodeLength (&Node
.F1394
.Header
, sizeof (F1394_DEVICE_PATH
));
753 Node
.F1394
.Guid
= Drive
->Parameters
.DevicePath
.FireWire
.Guid
;
755 } else if (AsciiStrnCmp ("FIBRE", Drive
->Parameters
.InterfaceType
, 5) == 0) {
759 Node
.FibreChannel
.Header
.Type
= MESSAGING_DEVICE_PATH
;
760 Node
.FibreChannel
.Header
.SubType
= MSG_FIBRECHANNEL_DP
;
761 SetDevicePathNodeLength (&Node
.FibreChannel
.Header
, sizeof (FIBRECHANNEL_DEVICE_PATH
));
762 Node
.FibreChannel
.WWN
= Drive
->Parameters
.DevicePath
.FibreChannel
.Wwn
;
763 Node
.FibreChannel
.Lun
= Drive
->Parameters
.DevicePath
.FibreChannel
.Lun
;
768 DEBUG_BLKIO
, "It is unrecognized EDD 3.0 device, Drive Number = %x, InterfaceType = %s\n",
770 Drive
->Parameters
.InterfaceType
776 if (Node
.DevPath
.Type
== 0) {
777 return EFI_UNSUPPORTED
;
780 *DevicePath
= AppendDevicePathNode (BaseDevicePath
, &Node
.DevPath
);