Signed-off-by: li-elvin Reviewed-by: erictian git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12084 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1496 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1496 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Routines that use BIOS to support INT 13 devices.
 | |
| 
 | |
| Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>
 | |
| 
 | |
| This program and the accompanying materials
 | |
| are licensed and made available under the terms and conditions
 | |
| of the BSD License which accompanies this distribution.  The
 | |
| full text of the license may be found at
 | |
| http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "BiosBlkIo.h"
 | |
| 
 | |
| //
 | |
| // Module global variables
 | |
| //
 | |
| //
 | |
| // Address packet is a buffer under 1 MB for all version EDD calls
 | |
| //
 | |
| extern EDD_DEVICE_ADDRESS_PACKET  *mEddBufferUnder1Mb;
 | |
| 
 | |
| //
 | |
| // This is a buffer for INT 13h func 48 information
 | |
| //
 | |
| extern BIOS_LEGACY_DRIVE          *mLegacyDriverUnder1Mb;
 | |
| 
 | |
| //
 | |
| // Buffer of 0xFE00 bytes for EDD 1.1 transfer must be under 1 MB
 | |
| //  0xFE00 bytes is the max transfer size supported.
 | |
| //
 | |
| extern VOID                       *mEdd11Buffer;
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Initialize block I/O device instance
 | |
| 
 | |
|   @param  Dev   Instance of block I/O device instance
 | |
| 
 | |
|   @retval TRUE  Initialization succeeds.
 | |
|   @retval FALSE Initialization fails.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| BiosInitBlockIo (
 | |
|   IN  BIOS_BLOCK_IO_DEV         *Dev
 | |
|   )
 | |
| {
 | |
|   EFI_BLOCK_IO_PROTOCOL *BlockIo;
 | |
|   EFI_BLOCK_IO_MEDIA    *BlockMedia;
 | |
|   BIOS_LEGACY_DRIVE     *Bios;
 | |
| 
 | |
|   BlockIo         = &Dev->BlockIo;
 | |
|   BlockIo->Media  = &Dev->BlockMedia;
 | |
|   BlockMedia      = BlockIo->Media;
 | |
|   Bios            = &Dev->Bios;
 | |
| 
 | |
|   if (Int13GetDeviceParameters (Dev, Bios) != 0) {
 | |
|     if (Int13Extensions (Dev, Bios) != 0) {
 | |
|       BlockMedia->LastBlock = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
 | |
|       BlockMedia->BlockSize = (UINT32) Bios->Parameters.BytesPerSector;
 | |
| 
 | |
|       if ((Bios->Parameters.Flags & EDD_DEVICE_REMOVABLE) == EDD_DEVICE_REMOVABLE) {
 | |
|         BlockMedia->RemovableMedia = TRUE;
 | |
|       }
 | |
| 
 | |
|     } else {
 | |
|       //
 | |
|       // Legacy Interfaces
 | |
|       //
 | |
|       BlockMedia->BlockSize = 512;
 | |
|       BlockMedia->LastBlock = (Bios->MaxHead + 1) * Bios->MaxSector * (Bios->MaxCylinder + 1) - 1;
 | |
|     }
 | |
| 
 | |
|     DEBUG ((DEBUG_INIT, "BlockSize = %d  LastBlock = %d\n", BlockMedia->BlockSize, BlockMedia->LastBlock));
 | |
| 
 | |
|     BlockMedia->LogicalPartition  = FALSE;
 | |
|     BlockMedia->WriteCaching      = FALSE;
 | |
| 
 | |
|     //
 | |
|     // BugBug: Need to set this for removable media devices if they do not
 | |
|     //  have media present
 | |
|     //
 | |
|     BlockMedia->ReadOnly      = FALSE;
 | |
|     BlockMedia->MediaPresent  = TRUE;
 | |
| 
 | |
|     BlockIo->Reset            = BiosBlockIoReset;
 | |
|     BlockIo->FlushBlocks      = BiosBlockIoFlushBlocks;
 | |
| 
 | |
|     if (!Bios->ExtendedInt13) {
 | |
|       //
 | |
|       // Legacy interfaces
 | |
|       //
 | |
|       BlockIo->ReadBlocks   = BiosReadLegacyDrive;
 | |
|       BlockIo->WriteBlocks  = BiosWriteLegacyDrive;
 | |
|     } else if ((Bios->EddVersion == EDD_VERSION_30) && (Bios->Extensions64Bit)) {
 | |
|       //
 | |
|       // EDD 3.0 Required for Device path, but extended reads are not required.
 | |
|       //
 | |
|       BlockIo->ReadBlocks   = Edd30BiosReadBlocks;
 | |
|       BlockIo->WriteBlocks  = Edd30BiosWriteBlocks;
 | |
|     } else {
 | |
|       //
 | |
|       // Assume EDD 1.1 - Read and Write functions.
 | |
|       //  This could be EDD 3.0 without Extensions64Bit being set.
 | |
|       // If it's EDD 1.1 this will work, but the device path will not
 | |
|       //  be correct. This will cause confusion to EFI OS installation.
 | |
|       //
 | |
|       BlockIo->ReadBlocks   = Edd11BiosReadBlocks;
 | |
|       BlockIo->WriteBlocks  = Edd11BiosWriteBlocks;
 | |
|     }
 | |
| 
 | |
|     BlockMedia->LogicalPartition  = FALSE;
 | |
|     BlockMedia->WriteCaching      = FALSE;
 | |
| 
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Gets parameters of block I/O device.
 | |
| 
 | |
|   @param  BiosBlockIoDev Instance of block I/O device.
 | |
|   @param  Drive          Legacy drive.
 | |
| 
 | |
|   @return  Result of device parameter retrieval.
 | |
|  
 | |
| **/
 | |
| UINTN
 | |
| Int13GetDeviceParameters (
 | |
|   IN  BIOS_BLOCK_IO_DEV    *BiosBlockIoDev,
 | |
|   IN  BIOS_LEGACY_DRIVE    *Drive
 | |
|   )
 | |
| {
 | |
|   UINTN                 CarryFlag;
 | |
|   UINT16                Cylinder;
 | |
|   EFI_IA32_REGISTER_SET Regs;
 | |
| 
 | |
|   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
 | |
| 
 | |
|   Regs.H.AH = 0x08;
 | |
|   Regs.H.DL = Drive->Number;
 | |
|   CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
 | |
|   DEBUG ((DEBUG_INIT, "Int13GetDeviceParameters: INT 13 08 DL=%02x : CF=%d AH=%02x\n", Drive->Number, CarryFlag, Regs.H.AH));
 | |
|   if (CarryFlag != 0 || Regs.H.AH != 0x00) {
 | |
|     Drive->ErrorCode = Regs.H.AH;
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   if (Drive->Floppy) {
 | |
|     if (Regs.H.BL == 0x10) {
 | |
|       Drive->AtapiFloppy = TRUE;
 | |
|     } else {
 | |
|       Drive->MaxHead      = Regs.H.DH;
 | |
|       Drive->MaxSector    = Regs.H.CL;
 | |
|       Drive->MaxCylinder  = Regs.H.CH;
 | |
|       if (Drive->MaxSector == 0) {
 | |
|         //
 | |
|         // BugBug: You can not trust the Carry flag.
 | |
|         //
 | |
|         return FALSE;
 | |
|       }
 | |
|     }
 | |
|   } else {
 | |
|     Drive->MaxHead  = (UINT8) (Regs.H.DH & 0x3f);
 | |
|     Cylinder        = (UINT16) (((UINT16) Regs.H.DH & 0xc0) << 4);
 | |
|     Cylinder        = (UINT16) (Cylinder | ((UINT16) Regs.H.CL & 0xc0) << 2);
 | |
|     Drive->MaxCylinder  = (UINT16) (Cylinder + Regs.H.CH);
 | |
|     Drive->MaxSector    = (UINT8) (Regs.H.CL & 0x3f);
 | |
|   }
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Extension of INT13 call.
 | |
| 
 | |
|   @param  BiosBlockIoDev Instance of block I/O device.
 | |
|   @param  Drive          Legacy drive.
 | |
| 
 | |
|   @return  Result of this extension.
 | |
|  
 | |
| **/
 | |
| UINTN
 | |
| Int13Extensions (
 | |
|   IN  BIOS_BLOCK_IO_DEV    *BiosBlockIoDev,
 | |
|   IN  BIOS_LEGACY_DRIVE    *Drive
 | |
|   )
 | |
| {
 | |
|   INTN                  CarryFlag;
 | |
|   EFI_IA32_REGISTER_SET Regs;
 | |
| 
 | |
|   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
 | |
| 
 | |
|   Regs.H.AH = 0x41;
 | |
|   Regs.X.BX = 0x55aa;
 | |
|   Regs.H.DL = Drive->Number;
 | |
|   CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
 | |
|   DEBUG ((DEBUG_INIT, "Int13Extensions: INT 13 41 DL=%02x : CF=%d BX=%04x\n", Drive->Number, CarryFlag, Regs.X.BX));
 | |
|   if (CarryFlag != 0 || Regs.X.BX != 0xaa55) {
 | |
|     Drive->ExtendedInt13            = FALSE;
 | |
|     Drive->DriveLockingAndEjecting  = FALSE;
 | |
|     Drive->Edd                      = FALSE;
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   Drive->EddVersion               = Regs.H.AH;
 | |
|   Drive->ExtendedInt13            = (BOOLEAN) ((Regs.X.CX & 0x01) == 0x01);
 | |
|   Drive->DriveLockingAndEjecting  = (BOOLEAN) ((Regs.X.CX & 0x02) == 0x02);
 | |
|   Drive->Edd                      = (BOOLEAN) ((Regs.X.CX & 0x04) == 0x04);
 | |
|   Drive->Extensions64Bit          = (BOOLEAN) (Regs.X.CX & 0x08);
 | |
| 
 | |
|   Drive->ParametersValid          = (UINT8) GetDriveParameters (BiosBlockIoDev, Drive);
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Gets parameters of legacy drive.
 | |
| 
 | |
|   @param  BiosBlockIoDev Instance of block I/O device.
 | |
|   @param  Drive          Legacy drive.
 | |
| 
 | |
|   @return  Result of drive parameter retrieval.
 | |
|  
 | |
| **/
 | |
| UINTN
 | |
| GetDriveParameters (
 | |
|   IN  BIOS_BLOCK_IO_DEV   *BiosBlockIoDev,
 | |
|   IN  BIOS_LEGACY_DRIVE   *Drive
 | |
|   )
 | |
| {
 | |
|   INTN                  CarryFlag;
 | |
|   EFI_IA32_REGISTER_SET Regs;
 | |
|   UINTN                 PointerMath;
 | |
| 
 | |
|   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
 | |
| 
 | |
|   Regs.H.AH = 0x48;
 | |
|   Regs.H.DL = Drive->Number;
 | |
| 
 | |
|   //
 | |
|   // EDD Buffer must be passed in with max buffer size as first entry in the buffer
 | |
|   //
 | |
|   mLegacyDriverUnder1Mb->Parameters.StructureSize = (UINT16) sizeof (EDD_DRIVE_PARAMETERS);
 | |
|   Regs.X.DS = EFI_SEGMENT ((UINTN)(&mLegacyDriverUnder1Mb->Parameters));
 | |
|   Regs.X.SI = EFI_OFFSET ((UINTN)(&mLegacyDriverUnder1Mb->Parameters));
 | |
|   CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
 | |
|   DEBUG ((DEBUG_INIT, "GetDriveParameters: INT 13 48 DL=%02x : CF=%d AH=%02x\n", Drive->Number, CarryFlag, Regs.H.AH));
 | |
|   if (CarryFlag != 0 || Regs.H.AH != 0x00) {
 | |
|     Drive->ErrorCode = Regs.H.AH;
 | |
|     SetMem (&Drive->Parameters, sizeof (Drive->Parameters), 0xaf);
 | |
|     return FALSE;
 | |
|   }
 | |
|   //
 | |
|   // We only have one buffer < 1MB, so copy into our instance data
 | |
|   //
 | |
|   CopyMem (
 | |
|     &Drive->Parameters,
 | |
|     &mLegacyDriverUnder1Mb->Parameters,
 | |
|     sizeof (Drive->Parameters)
 | |
|     );
 | |
| 
 | |
|   if (Drive->AtapiFloppy) {
 | |
|     //
 | |
|     // Sense Media Type
 | |
|     //
 | |
|     Regs.H.AH = 0x20;
 | |
|     Regs.H.DL = Drive->Number;
 | |
|     CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
 | |
|     DEBUG ((DEBUG_INIT, "GetDriveParameters: INT 13 20 DL=%02x : CF=%d AL=%02x\n", Drive->Number, CarryFlag, Regs.H.AL));
 | |
|     if (CarryFlag != 0) {
 | |
|       //
 | |
|       // Media not present or unknown media present
 | |
|       //
 | |
|       if ((Drive->Parameters.Flags & EDD_GEOMETRY_VALID) == EDD_GEOMETRY_VALID) {
 | |
|         Drive->MaxHead    = (UINT8) (Drive->Parameters.MaxHeads - 1);
 | |
|         Drive->MaxSector  = (UINT8) Drive->Parameters.SectorsPerTrack;
 | |
|         ASSERT (Drive->MaxSector != 0);
 | |
|         Drive->MaxCylinder = (UINT16) (Drive->Parameters.MaxCylinders - 1);
 | |
|       } else {
 | |
|         Drive->MaxHead      = 0;
 | |
|         Drive->MaxSector    = 1;
 | |
|         Drive->MaxCylinder  = 0;
 | |
|       }
 | |
| 
 | |
|     } else {
 | |
|       //
 | |
|       // Media Present
 | |
|       //
 | |
|       switch (Regs.H.AL) {
 | |
|       case 0x03:
 | |
|         //
 | |
|         // 720 KB
 | |
|         //
 | |
|         Drive->MaxHead      = 1;
 | |
|         Drive->MaxSector    = 9;
 | |
|         Drive->MaxCylinder  = 79;
 | |
|         break;
 | |
| 
 | |
|       case 0x04:
 | |
|         //
 | |
|         // 1.44MB
 | |
|         //
 | |
|         Drive->MaxHead      = 1;
 | |
|         Drive->MaxSector    = 18;
 | |
|         Drive->MaxCylinder  = 79;
 | |
|         break;
 | |
| 
 | |
|       case 0x06:
 | |
|         //
 | |
|         // 2.88MB
 | |
|         //
 | |
|         Drive->MaxHead      = 1;
 | |
|         Drive->MaxSector    = 36;
 | |
|         Drive->MaxCylinder  = 79;
 | |
|         break;
 | |
| 
 | |
|       case 0x0C:
 | |
|         //
 | |
|         // 360 KB
 | |
|         //
 | |
|         Drive->MaxHead      = 1;
 | |
|         Drive->MaxSector    = 9;
 | |
|         Drive->MaxCylinder  = 39;
 | |
|         break;
 | |
| 
 | |
|       case 0x0D:
 | |
|         //
 | |
|         // 1.2 MB
 | |
|         //
 | |
|         Drive->MaxHead      = 1;
 | |
|         Drive->MaxSector    = 15;
 | |
|         Drive->MaxCylinder  = 79;
 | |
|         break;
 | |
| 
 | |
|       case 0x0E:
 | |
|         //
 | |
|         // Toshiba 3 mode
 | |
|         //
 | |
|       case 0x0F:
 | |
|         //
 | |
|         // NEC 3 mode
 | |
|         //
 | |
|       case 0x10:
 | |
|         //
 | |
|         // Default Media
 | |
|         //
 | |
|         if ((Drive->Parameters.Flags & EDD_GEOMETRY_VALID) == EDD_GEOMETRY_VALID) {
 | |
|           Drive->MaxHead    = (UINT8) (Drive->Parameters.MaxHeads - 1);
 | |
|           Drive->MaxSector  = (UINT8) Drive->Parameters.SectorsPerTrack;
 | |
|           ASSERT (Drive->MaxSector != 0);
 | |
|           Drive->MaxCylinder = (UINT16) (Drive->Parameters.MaxCylinders - 1);
 | |
|         } else {
 | |
|           Drive->MaxHead      = 0;
 | |
|           Drive->MaxSector    = 1;
 | |
|           Drive->MaxCylinder  = 0;
 | |
|         }
 | |
|         break;
 | |
| 
 | |
|       default:
 | |
|         //
 | |
|         // Unknown media type.
 | |
|         //
 | |
|         Drive->MaxHead      = 0;
 | |
|         Drive->MaxSector    = 1;
 | |
|         Drive->MaxCylinder  = 0;
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     Drive->Parameters.PhysicalSectors = (Drive->MaxHead + 1) * Drive->MaxSector * (Drive->MaxCylinder + 1);
 | |
|     Drive->Parameters.BytesPerSector  = 512;
 | |
|   }
 | |
|   //
 | |
|   // This data comes from the BIOS so it may not allways be valid
 | |
|   //  since the BIOS may reuse this buffer for future accesses
 | |
|   //
 | |
|   PointerMath = EFI_SEGMENT (Drive->Parameters.Fdpt) << 4;
 | |
|   PointerMath += EFI_OFFSET (Drive->Parameters.Fdpt);
 | |
|   Drive->FdptPointer = (VOID *) PointerMath;
 | |
| 
 | |
|   return TRUE;
 | |
| }
 | |
| //
 | |
| // Block IO Routines
 | |
| //
 | |
| 
 | |
| /**
 | |
|   Read BufferSize bytes from Lba into Buffer.
 | |
| 
 | |
|   @param  This       Indicates a pointer to the calling context.
 | |
|   @param  MediaId    Id of the media, changes every time the media is replaced.
 | |
|   @param  Lba        The starting Logical Block Address to read from
 | |
|   @param  BufferSize Size of Buffer, must be a multiple of device block size.
 | |
|   @param  Buffer     A pointer to the destination buffer for the data. The caller is
 | |
|                      responsible for either having implicit or explicit ownership of the buffer.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The data was read correctly from the device.
 | |
|   @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.
 | |
|   @retval EFI_NO_MEDIA          There is no media in the device.
 | |
|   @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.
 | |
|   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
 | |
|   @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, 
 | |
|                                 or the buffer is not on proper alignment.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| Edd30BiosReadBlocks (
 | |
|   IN  EFI_BLOCK_IO_PROTOCOL *This,
 | |
|   IN  UINT32                MediaId,
 | |
|   IN  EFI_LBA               Lba,
 | |
|   IN  UINTN                 BufferSize,
 | |
|   OUT VOID                  *Buffer
 | |
|   )
 | |
| {
 | |
|   EFI_BLOCK_IO_MEDIA        *Media;
 | |
|   BIOS_BLOCK_IO_DEV         *BiosBlockIoDev;
 | |
|   EDD_DEVICE_ADDRESS_PACKET *AddressPacket;
 | |
|   //
 | |
|   // I exist only for readability
 | |
|   //
 | |
|   EFI_IA32_REGISTER_SET     Regs;
 | |
|   UINT64                    TransferBuffer;
 | |
|   UINTN                     NumberOfBlocks;
 | |
|   UINTN                     TransferByteSize;
 | |
|   UINTN                     BlockSize;
 | |
|   BIOS_LEGACY_DRIVE         *Bios;
 | |
|   UINTN                     CarryFlag;
 | |
|   UINTN                     MaxTransferBlocks;
 | |
|   EFI_BLOCK_IO_PROTOCOL     *BlockIo;
 | |
| 
 | |
|   Media     = This->Media;
 | |
|   BlockSize = Media->BlockSize;
 | |
| 
 | |
|   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
 | |
| 
 | |
|   if (MediaId != Media->MediaId) {
 | |
|     return EFI_MEDIA_CHANGED;
 | |
|   }
 | |
| 
 | |
|   if (Lba > Media->LastBlock) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (BufferSize % BlockSize != 0) {
 | |
|     return EFI_BAD_BUFFER_SIZE;
 | |
|   }
 | |
| 
 | |
|   if (Buffer == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (BufferSize == 0) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   BiosBlockIoDev    = BIOS_BLOCK_IO_FROM_THIS (This);
 | |
|   AddressPacket     = mEddBufferUnder1Mb;
 | |
| 
 | |
|   MaxTransferBlocks = MAX_EDD11_XFER / BlockSize;
 | |
| 
 | |
|   TransferBuffer    = (UINT64)(UINTN) Buffer;
 | |
|   for (; BufferSize > 0;) {
 | |
|     NumberOfBlocks  = BufferSize / BlockSize;
 | |
|     NumberOfBlocks  = NumberOfBlocks > MaxTransferBlocks ? MaxTransferBlocks : NumberOfBlocks;
 | |
|     //
 | |
|     // Max transfer MaxTransferBlocks
 | |
|     //
 | |
|     AddressPacket->PacketSizeInBytes  = (UINT8) sizeof (EDD_DEVICE_ADDRESS_PACKET);
 | |
|     AddressPacket->Zero               = 0;
 | |
|     AddressPacket->NumberOfBlocks     = (UINT8) NumberOfBlocks;
 | |
|     AddressPacket->Zero2              = 0;
 | |
|     AddressPacket->SegOffset          = 0xffffffff;
 | |
|     AddressPacket->Lba                = (UINT64) Lba;
 | |
|     AddressPacket->TransferBuffer     = TransferBuffer;
 | |
| 
 | |
|     Regs.H.AH                         = 0x42;
 | |
|     Regs.H.DL                         = BiosBlockIoDev->Bios.Number;
 | |
|     Regs.X.SI                         = EFI_OFFSET (AddressPacket);
 | |
|     Regs.X.DS                         = EFI_SEGMENT (AddressPacket);
 | |
| 
 | |
|     CarryFlag                         = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
 | |
|     DEBUG (
 | |
|       (
 | |
|       DEBUG_BLKIO, "Edd30BiosReadBlocks: INT 13 42 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number,
 | |
|       CarryFlag, Regs.H.AH
 | |
|       )
 | |
|       );
 | |
| 
 | |
|     Media->MediaPresent = TRUE;
 | |
|     if (CarryFlag != 0) {
 | |
|       //
 | |
|       // Return Error Status
 | |
|       //
 | |
|       BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
 | |
|       if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
 | |
|         Media->MediaId++;
 | |
|         Bios = &BiosBlockIoDev->Bios;
 | |
|         if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
 | |
|           if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
 | |
|             Media->LastBlock  = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
 | |
|             Media->BlockSize  = (UINT32) Bios->Parameters.BytesPerSector;
 | |
|           } else {
 | |
|             ASSERT (FALSE);
 | |
|           }
 | |
| 
 | |
|           Media->ReadOnly = FALSE;
 | |
|           gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
 | |
|           gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
 | |
|           return EFI_MEDIA_CHANGED;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (Media->RemovableMedia) {
 | |
|         Media->MediaPresent = FALSE;
 | |
|       }
 | |
| 
 | |
|       return EFI_DEVICE_ERROR;
 | |
|     }
 | |
| 
 | |
|     TransferByteSize  = NumberOfBlocks * BlockSize;
 | |
|     BufferSize        = BufferSize - TransferByteSize;
 | |
|     TransferBuffer += TransferByteSize;
 | |
|     Lba += NumberOfBlocks;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Write BufferSize bytes from Lba into Buffer.
 | |
| 
 | |
|   @param  This       Indicates a pointer to the calling context.
 | |
|   @param  MediaId    The media ID that the write request is for.
 | |
|   @param  Lba        The starting logical block address to be written. The caller is
 | |
|                      responsible for writing to only legitimate locations.
 | |
|   @param  BufferSize Size of Buffer, must be a multiple of device block size.
 | |
|   @param  Buffer     A pointer to the source buffer for the data.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The data was written correctly to the device.
 | |
|   @retval EFI_WRITE_PROTECTED   The device can not be written to.
 | |
|   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
 | |
|   @retval EFI_NO_MEDIA          There is no media in the device.
 | |
|   @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
 | |
|   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
 | |
|   @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, 
 | |
|                                 or the buffer is not on proper alignment.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| Edd30BiosWriteBlocks (
 | |
|   IN  EFI_BLOCK_IO_PROTOCOL *This,
 | |
|   IN  UINT32                MediaId,
 | |
|   IN  EFI_LBA               Lba,
 | |
|   IN  UINTN                 BufferSize,
 | |
|   OUT VOID                  *Buffer
 | |
|   )
 | |
| {
 | |
|   EFI_BLOCK_IO_MEDIA        *Media;
 | |
|   BIOS_BLOCK_IO_DEV         *BiosBlockIoDev;
 | |
|   EDD_DEVICE_ADDRESS_PACKET *AddressPacket;
 | |
|   //
 | |
|   // I exist only for readability
 | |
|   //
 | |
|   EFI_IA32_REGISTER_SET     Regs;
 | |
|   UINT64                    TransferBuffer;
 | |
|   UINTN                     NumberOfBlocks;
 | |
|   UINTN                     TransferByteSize;
 | |
|   UINTN                     BlockSize;
 | |
|   BIOS_LEGACY_DRIVE         *Bios;
 | |
|   UINTN                     CarryFlag;
 | |
|   UINTN                     MaxTransferBlocks;
 | |
|   EFI_BLOCK_IO_PROTOCOL     *BlockIo;
 | |
| 
 | |
|   Media     = This->Media;
 | |
|   BlockSize = Media->BlockSize;
 | |
| 
 | |
|   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
 | |
| 
 | |
|   if (MediaId != Media->MediaId) {
 | |
|     return EFI_MEDIA_CHANGED;
 | |
|   }
 | |
| 
 | |
|   if (Lba > Media->LastBlock) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (BufferSize % BlockSize != 0) {
 | |
|     return EFI_BAD_BUFFER_SIZE;
 | |
|   }
 | |
| 
 | |
|   if (Buffer == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (BufferSize == 0) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   BiosBlockIoDev    = BIOS_BLOCK_IO_FROM_THIS (This);
 | |
|   AddressPacket     = mEddBufferUnder1Mb;
 | |
| 
 | |
|   MaxTransferBlocks = MAX_EDD11_XFER / BlockSize;
 | |
| 
 | |
|   TransferBuffer    = (UINT64)(UINTN) Buffer;
 | |
|   for (; BufferSize > 0;) {
 | |
|     NumberOfBlocks  = BufferSize / BlockSize;
 | |
|     NumberOfBlocks  = NumberOfBlocks > MaxTransferBlocks ? MaxTransferBlocks : NumberOfBlocks;
 | |
|     //
 | |
|     // Max transfer MaxTransferBlocks
 | |
|     //
 | |
|     AddressPacket->PacketSizeInBytes  = (UINT8) sizeof (EDD_DEVICE_ADDRESS_PACKET);
 | |
|     AddressPacket->Zero               = 0;
 | |
|     AddressPacket->NumberOfBlocks     = (UINT8) NumberOfBlocks;
 | |
|     AddressPacket->Zero2              = 0;
 | |
|     AddressPacket->SegOffset          = 0xffffffff;
 | |
|     AddressPacket->Lba                = (UINT64) Lba;
 | |
|     AddressPacket->TransferBuffer     = TransferBuffer;
 | |
| 
 | |
|     Regs.H.AH                         = 0x43;
 | |
|     Regs.H.AL                         = 0x00;
 | |
|     //
 | |
|     // Write Verify Off
 | |
|     //
 | |
|     Regs.H.DL = (UINT8) (BiosBlockIoDev->Bios.Number);
 | |
|     Regs.X.SI = EFI_OFFSET (AddressPacket);
 | |
|     Regs.X.DS = EFI_SEGMENT (AddressPacket);
 | |
| 
 | |
|     CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
 | |
|     DEBUG (
 | |
|       (
 | |
|       DEBUG_BLKIO, "Edd30BiosWriteBlocks: INT 13 43 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number,
 | |
|       CarryFlag, Regs.H.AH
 | |
|       )
 | |
|       );
 | |
| 
 | |
|     Media->MediaPresent = TRUE;
 | |
|     if (CarryFlag != 0) {
 | |
|       //
 | |
|       // Return Error Status
 | |
|       //
 | |
|       BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
 | |
|       if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
 | |
|         Media->MediaId++;
 | |
|         Bios = &BiosBlockIoDev->Bios;
 | |
|         if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
 | |
|           if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
 | |
|             Media->LastBlock  = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
 | |
|             Media->BlockSize  = (UINT32) Bios->Parameters.BytesPerSector;
 | |
|           } else {
 | |
|             ASSERT (FALSE);
 | |
|           }
 | |
| 
 | |
|           Media->ReadOnly = FALSE;
 | |
|           gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
 | |
|           gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
 | |
|           return EFI_MEDIA_CHANGED;
 | |
|         }
 | |
|       } else if (BiosBlockIoDev->Bios.ErrorCode == BIOS_WRITE_PROTECTED) {
 | |
|         Media->ReadOnly = TRUE;
 | |
|         return EFI_WRITE_PROTECTED;
 | |
|       }
 | |
| 
 | |
|       if (Media->RemovableMedia) {
 | |
|         Media->MediaPresent = FALSE;
 | |
|       }
 | |
| 
 | |
|       return EFI_DEVICE_ERROR;
 | |
|     }
 | |
| 
 | |
|     Media->ReadOnly   = FALSE;
 | |
|     TransferByteSize  = NumberOfBlocks * BlockSize;
 | |
|     BufferSize        = BufferSize - TransferByteSize;
 | |
|     TransferBuffer += TransferByteSize;
 | |
|     Lba += NumberOfBlocks;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Flush the Block Device.
 | |
| 
 | |
|   @param  This              Indicates a pointer to the calling context.
 | |
| 
 | |
|   @retval EFI_SUCCESS       All outstanding data was written to the device
 | |
|   @retval EFI_DEVICE_ERROR  The device reported an error while writting back the data
 | |
|   @retval EFI_NO_MEDIA      There is no media in the device.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| BiosBlockIoFlushBlocks (
 | |
|   IN  EFI_BLOCK_IO_PROTOCOL  *This
 | |
|   )
 | |
| {
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Reset the Block Device.
 | |
| 
 | |
|   @param  This                 Indicates a pointer to the calling context.
 | |
|   @param  ExtendedVerification Driver may perform diagnostics on reset.
 | |
| 
 | |
|   @retval EFI_SUCCESS          The device was reset.
 | |
|   @retval EFI_DEVICE_ERROR     The device is not functioning properly and could
 | |
|                                not be reset.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| BiosBlockIoReset (
 | |
|   IN  EFI_BLOCK_IO_PROTOCOL *This,
 | |
|   IN  BOOLEAN               ExtendedVerification
 | |
|   )
 | |
| {
 | |
|   BIOS_BLOCK_IO_DEV     *BiosBlockIoDev;
 | |
|   EFI_IA32_REGISTER_SET Regs;
 | |
|   UINTN                 CarryFlag;
 | |
| 
 | |
|   BiosBlockIoDev  = BIOS_BLOCK_IO_FROM_THIS (This);
 | |
| 
 | |
|   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
 | |
| 
 | |
|   Regs.H.AH       = 0x00;
 | |
|   Regs.H.DL       = BiosBlockIoDev->Bios.Number;
 | |
|   CarryFlag       = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
 | |
|   DEBUG (
 | |
|     (
 | |
|     DEBUG_INIT, "BiosBlockIoReset: INT 13 00 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number, CarryFlag,
 | |
|     Regs.H.AH
 | |
|     )
 | |
|     );
 | |
|   if (CarryFlag != 0) {
 | |
|     if (Regs.H.AL == BIOS_RESET_FAILED) {
 | |
|       Regs.H.AH = 0x00;
 | |
|       Regs.H.DL = BiosBlockIoDev->Bios.Number;
 | |
|       CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
 | |
|       DEBUG (
 | |
|         (
 | |
|         DEBUG_INIT, "BiosBlockIoReset: INT 13 00 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number, CarryFlag,
 | |
|         Regs.H.AH
 | |
|         )
 | |
|         );
 | |
|       if (CarryFlag != 0) {
 | |
|         BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
 | |
|         return EFI_DEVICE_ERROR;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| //
 | |
| //
 | |
| // These functions need to double buffer all data under 1MB!
 | |
| //
 | |
| //
 | |
| 
 | |
| /**
 | |
|   Read BufferSize bytes from Lba into Buffer.
 | |
| 
 | |
|   @param  This       Indicates a pointer to the calling context.
 | |
|   @param  MediaId    Id of the media, changes every time the media is replaced.
 | |
|   @param  Lba        The starting Logical Block Address to read from
 | |
|   @param  BufferSize Size of Buffer, must be a multiple of device block size.
 | |
|   @param  Buffer     A pointer to the destination buffer for the data. The caller is
 | |
|                      responsible for either having implicit or explicit ownership of the buffer.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The data was read correctly from the device.
 | |
|   @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.
 | |
|   @retval EFI_NO_MEDIA          There is no media in the device.
 | |
|   @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.
 | |
|   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
 | |
|   @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, 
 | |
|                                 or the buffer is not on proper alignment.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| Edd11BiosReadBlocks (
 | |
|   IN  EFI_BLOCK_IO_PROTOCOL *This,
 | |
|   IN  UINT32                MediaId,
 | |
|   IN  EFI_LBA               Lba,
 | |
|   IN  UINTN                 BufferSize,
 | |
|   OUT VOID                  *Buffer
 | |
|   )
 | |
| {
 | |
|   EFI_BLOCK_IO_MEDIA        *Media;
 | |
|   BIOS_BLOCK_IO_DEV         *BiosBlockIoDev;
 | |
|   EDD_DEVICE_ADDRESS_PACKET *AddressPacket;
 | |
|   //
 | |
|   // I exist only for readability
 | |
|   //
 | |
|   EFI_IA32_REGISTER_SET     Regs;
 | |
|   UINT64                    TransferBuffer;
 | |
|   UINTN                     NumberOfBlocks;
 | |
|   UINTN                     TransferByteSize;
 | |
|   UINTN                     BlockSize;
 | |
|   BIOS_LEGACY_DRIVE         *Bios;
 | |
|   UINTN                     CarryFlag;
 | |
|   UINTN                     MaxTransferBlocks;
 | |
|   EFI_BLOCK_IO_PROTOCOL     *BlockIo;
 | |
| 
 | |
|   Media     = This->Media;
 | |
|   BlockSize = Media->BlockSize;
 | |
| 
 | |
|   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
 | |
| 
 | |
|   if (MediaId != Media->MediaId) {
 | |
|     return EFI_MEDIA_CHANGED;
 | |
|   }
 | |
| 
 | |
|   if (Lba > Media->LastBlock) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (BufferSize % BlockSize != 0) {
 | |
|     return EFI_BAD_BUFFER_SIZE;
 | |
|   }
 | |
| 
 | |
|   if (Buffer == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (BufferSize == 0) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   BiosBlockIoDev    = BIOS_BLOCK_IO_FROM_THIS (This);
 | |
|   AddressPacket     = mEddBufferUnder1Mb;
 | |
| 
 | |
|   MaxTransferBlocks = MAX_EDD11_XFER / BlockSize;
 | |
| 
 | |
|   TransferBuffer    = (UINT64)(UINTN) mEdd11Buffer;
 | |
|   for (; BufferSize > 0;) {
 | |
|     NumberOfBlocks  = BufferSize / BlockSize;
 | |
|     NumberOfBlocks  = NumberOfBlocks > MaxTransferBlocks ? MaxTransferBlocks : NumberOfBlocks;
 | |
|     //
 | |
|     // Max transfer MaxTransferBlocks
 | |
|     //
 | |
|     AddressPacket->PacketSizeInBytes  = (UINT8) sizeof (EDD_DEVICE_ADDRESS_PACKET);
 | |
|     AddressPacket->Zero               = 0;
 | |
|     AddressPacket->NumberOfBlocks     = (UINT8) NumberOfBlocks;
 | |
|     AddressPacket->Zero2              = 0;
 | |
|     //
 | |
|     // TransferBuffer has been 4KB alignment. Normalize TransferBuffer to make offset as 0 in seg:offset
 | |
|     // format to transfer maximum 127 blocks of data.
 | |
|     // Otherwise when offset adding data size exceeds 0xFFFF, if OpROM does not normalize TransferBuffer,
 | |
|     // INT13 function 42H will return data boundary error 09H.
 | |
|     //
 | |
|     AddressPacket->SegOffset = (UINT32) ((TransferBuffer >> 4) << 16);
 | |
|     AddressPacket->Lba  = (UINT64) Lba;
 | |
| 
 | |
|     Regs.H.AH           = 0x42;
 | |
|     Regs.H.DL           = BiosBlockIoDev->Bios.Number;
 | |
|     Regs.X.SI           = EFI_OFFSET (AddressPacket);
 | |
|     Regs.X.DS           = EFI_SEGMENT (AddressPacket);
 | |
| 
 | |
|     CarryFlag           = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
 | |
|     DEBUG (
 | |
|       (
 | |
|       DEBUG_BLKIO, "Edd11BiosReadBlocks: INT 13 42 DL=%02x : CF=%d AH=%02x : LBA 0x%lx  Block(s) %0d \n",
 | |
|       BiosBlockIoDev->Bios.Number, CarryFlag, Regs.H.AH, Lba, NumberOfBlocks
 | |
|       )
 | |
|       );
 | |
|     Media->MediaPresent = TRUE;
 | |
|     if (CarryFlag != 0) {
 | |
|       //
 | |
|       // Return Error Status
 | |
|       //
 | |
|       BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
 | |
|       if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
 | |
|         Media->MediaId++;
 | |
|         Bios = &BiosBlockIoDev->Bios;
 | |
|         if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
 | |
|           if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
 | |
|             Media->LastBlock  = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
 | |
|             Media->BlockSize  = (UINT32) Bios->Parameters.BytesPerSector;
 | |
|           } else {
 | |
|             ASSERT (FALSE);
 | |
|           }
 | |
| 
 | |
|           Media->ReadOnly = FALSE;
 | |
|           gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
 | |
|           gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
 | |
|           return EFI_MEDIA_CHANGED;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (Media->RemovableMedia) {
 | |
|         Media->MediaPresent = FALSE;
 | |
|       }
 | |
| 
 | |
|       return EFI_DEVICE_ERROR;
 | |
|     }
 | |
| 
 | |
|     TransferByteSize = NumberOfBlocks * BlockSize;
 | |
|     CopyMem (Buffer, (VOID *) (UINTN) TransferBuffer, TransferByteSize);
 | |
|     BufferSize  = BufferSize - TransferByteSize;
 | |
|     Buffer      = (VOID *) ((UINT8 *) Buffer + TransferByteSize);
 | |
|     Lba += NumberOfBlocks;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Write BufferSize bytes from Lba into Buffer.
 | |
| 
 | |
|   @param  This       Indicates a pointer to the calling context.
 | |
|   @param  MediaId    The media ID that the write request is for.
 | |
|   @param  Lba        The starting logical block address to be written. The caller is
 | |
|                      responsible for writing to only legitimate locations.
 | |
|   @param  BufferSize Size of Buffer, must be a multiple of device block size.
 | |
|   @param  Buffer     A pointer to the source buffer for the data.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The data was written correctly to the device.
 | |
|   @retval EFI_WRITE_PROTECTED   The device can not be written to.
 | |
|   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
 | |
|   @retval EFI_NO_MEDIA          There is no media in the device.
 | |
|   @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
 | |
|   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
 | |
|   @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, 
 | |
|                                 or the buffer is not on proper alignment.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| Edd11BiosWriteBlocks (
 | |
|   IN  EFI_BLOCK_IO_PROTOCOL *This,
 | |
|   IN  UINT32                MediaId,
 | |
|   IN  EFI_LBA               Lba,
 | |
|   IN  UINTN                 BufferSize,
 | |
|   OUT VOID                  *Buffer
 | |
|   )
 | |
| {
 | |
|   EFI_BLOCK_IO_MEDIA        *Media;
 | |
|   BIOS_BLOCK_IO_DEV         *BiosBlockIoDev;
 | |
|   EDD_DEVICE_ADDRESS_PACKET *AddressPacket;
 | |
|   //
 | |
|   // I exist only for readability
 | |
|   //
 | |
|   EFI_IA32_REGISTER_SET     Regs;
 | |
|   UINT64                    TransferBuffer;
 | |
|   UINTN                     NumberOfBlocks;
 | |
|   UINTN                     TransferByteSize;
 | |
|   UINTN                     BlockSize;
 | |
|   BIOS_LEGACY_DRIVE         *Bios;
 | |
|   UINTN                     CarryFlag;
 | |
|   UINTN                     MaxTransferBlocks;
 | |
|   EFI_BLOCK_IO_PROTOCOL     *BlockIo;
 | |
| 
 | |
|   Media     = This->Media;
 | |
|   BlockSize = Media->BlockSize;
 | |
| 
 | |
|   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
 | |
| 
 | |
|   if (MediaId != Media->MediaId) {
 | |
|     return EFI_MEDIA_CHANGED;
 | |
|   }
 | |
| 
 | |
|   if (Lba > Media->LastBlock) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (BufferSize % BlockSize != 0) {
 | |
|     return EFI_BAD_BUFFER_SIZE;
 | |
|   }
 | |
| 
 | |
|   if (Buffer == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (BufferSize == 0) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   BiosBlockIoDev    = BIOS_BLOCK_IO_FROM_THIS (This);
 | |
|   AddressPacket     = mEddBufferUnder1Mb;
 | |
| 
 | |
|   MaxTransferBlocks = MAX_EDD11_XFER / BlockSize;
 | |
| 
 | |
|   TransferBuffer    = (UINT64)(UINTN) mEdd11Buffer;
 | |
|   for (; BufferSize > 0;) {
 | |
|     NumberOfBlocks  = BufferSize / BlockSize;
 | |
|     NumberOfBlocks  = NumberOfBlocks > MaxTransferBlocks ? MaxTransferBlocks : NumberOfBlocks;
 | |
|     //
 | |
|     // Max transfer MaxTransferBlocks
 | |
|     //
 | |
|     AddressPacket->PacketSizeInBytes  = (UINT8) sizeof (EDD_DEVICE_ADDRESS_PACKET);
 | |
|     AddressPacket->Zero               = 0;
 | |
|     AddressPacket->NumberOfBlocks     = (UINT8) NumberOfBlocks;
 | |
|     AddressPacket->Zero2              = 0;
 | |
|     //
 | |
|     // TransferBuffer has been 4KB alignment. Normalize TransferBuffer to make offset as 0 in seg:offset
 | |
|     // format to transfer maximum 127 blocks of data.
 | |
|     // Otherwise when offset adding data size exceeds 0xFFFF, if OpROM does not normalize TransferBuffer,
 | |
|     // INT13 function 42H will return data boundary error 09H.
 | |
|     //
 | |
|     AddressPacket->SegOffset = (UINT32) ((TransferBuffer >> 4) << 16);
 | |
|     AddressPacket->Lba  = (UINT64) Lba;
 | |
| 
 | |
|     Regs.H.AH           = 0x43;
 | |
|     Regs.H.AL           = 0x00;
 | |
|     //
 | |
|     // Write Verify disable
 | |
|     //
 | |
|     Regs.H.DL         = BiosBlockIoDev->Bios.Number;
 | |
|     Regs.X.SI         = EFI_OFFSET (AddressPacket);
 | |
|     Regs.X.DS         = EFI_SEGMENT (AddressPacket);
 | |
| 
 | |
|     TransferByteSize  = NumberOfBlocks * BlockSize;
 | |
|     CopyMem ((VOID *) (UINTN) TransferBuffer, Buffer, TransferByteSize);
 | |
| 
 | |
|     CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
 | |
|     DEBUG (
 | |
|       (
 | |
|       DEBUG_BLKIO, "Edd11BiosWriteBlocks: INT 13 43 DL=%02x : CF=%d AH=%02x\n: LBA 0x%lx  Block(s) %0d \n",
 | |
|       BiosBlockIoDev->Bios.Number, CarryFlag, Regs.H.AH, Lba, NumberOfBlocks
 | |
|       )
 | |
|       );
 | |
|     Media->MediaPresent = TRUE;
 | |
|     if (CarryFlag != 0) {
 | |
|       //
 | |
|       // Return Error Status
 | |
|       //
 | |
|       BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
 | |
|       if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
 | |
|         Media->MediaId++;
 | |
|         Bios = &BiosBlockIoDev->Bios;
 | |
|         if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
 | |
|           if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
 | |
|             Media->LastBlock  = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
 | |
|             Media->BlockSize  = (UINT32) Bios->Parameters.BytesPerSector;
 | |
|           } else {
 | |
|             ASSERT (FALSE);
 | |
|           }
 | |
| 
 | |
|           Media->ReadOnly = FALSE;
 | |
|           gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
 | |
|           gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
 | |
|           return EFI_MEDIA_CHANGED;
 | |
|         }
 | |
|       } else if (BiosBlockIoDev->Bios.ErrorCode == BIOS_WRITE_PROTECTED) {
 | |
|         Media->ReadOnly = TRUE;
 | |
|         return EFI_WRITE_PROTECTED;
 | |
|       }
 | |
| 
 | |
|       if (Media->RemovableMedia) {
 | |
|         Media->MediaPresent = FALSE;
 | |
|       }
 | |
| 
 | |
|       return EFI_DEVICE_ERROR;
 | |
|     }
 | |
| 
 | |
|     Media->ReadOnly = FALSE;
 | |
|     BufferSize      = BufferSize - TransferByteSize;
 | |
|     Buffer          = (VOID *) ((UINT8 *) Buffer + TransferByteSize);
 | |
|     Lba += NumberOfBlocks;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Read BufferSize bytes from Lba into Buffer.
 | |
| 
 | |
|   @param  This       Indicates a pointer to the calling context.
 | |
|   @param  MediaId    Id of the media, changes every time the media is replaced.
 | |
|   @param  Lba        The starting Logical Block Address to read from
 | |
|   @param  BufferSize Size of Buffer, must be a multiple of device block size.
 | |
|   @param  Buffer     A pointer to the destination buffer for the data. The caller is
 | |
|                      responsible for either having implicit or explicit ownership of the buffer.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The data was read correctly from the device.
 | |
|   @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.
 | |
|   @retval EFI_NO_MEDIA          There is no media in the device.
 | |
|   @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.
 | |
|   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
 | |
|   @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, 
 | |
|                                 or the buffer is not on proper alignment.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| BiosReadLegacyDrive (
 | |
|   IN  EFI_BLOCK_IO_PROTOCOL *This,
 | |
|   IN  UINT32                MediaId,
 | |
|   IN  EFI_LBA               Lba,
 | |
|   IN  UINTN                 BufferSize,
 | |
|   OUT VOID                  *Buffer
 | |
|   )
 | |
| {
 | |
|   EFI_BLOCK_IO_MEDIA    *Media;
 | |
|   BIOS_BLOCK_IO_DEV     *BiosBlockIoDev;
 | |
|   EFI_IA32_REGISTER_SET Regs;
 | |
|   UINTN                 UpperCylinder;
 | |
|   UINTN                 Temp;
 | |
|   UINTN                 Cylinder;
 | |
|   UINTN                 Head;
 | |
|   UINTN                 Sector;
 | |
|   UINTN                 NumberOfBlocks;
 | |
|   UINTN                 TransferByteSize;
 | |
|   UINTN                 ShortLba;
 | |
|   UINTN                 CheckLba;
 | |
|   UINTN                 BlockSize;
 | |
|   BIOS_LEGACY_DRIVE     *Bios;
 | |
|   UINTN                 CarryFlag;
 | |
|   UINTN                 Retry;
 | |
|   EFI_BLOCK_IO_PROTOCOL *BlockIo;
 | |
| 
 | |
|   Media     = This->Media;
 | |
|   BlockSize = Media->BlockSize;
 | |
| 
 | |
|   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
 | |
| 
 | |
|   if (MediaId != Media->MediaId) {
 | |
|     return EFI_MEDIA_CHANGED;
 | |
|   }
 | |
| 
 | |
|   if (Lba > Media->LastBlock) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (BufferSize % BlockSize != 0) {
 | |
|     return EFI_BAD_BUFFER_SIZE;
 | |
|   }
 | |
| 
 | |
|   if (Buffer == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (BufferSize == 0) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   BiosBlockIoDev  = BIOS_BLOCK_IO_FROM_THIS (This);
 | |
|   ShortLba        = (UINTN) Lba;
 | |
| 
 | |
|   while (BufferSize != 0) {
 | |
|     //
 | |
|     // Compute I/O location in Sector, Head, Cylinder format
 | |
|     //
 | |
|     Sector    = (ShortLba % BiosBlockIoDev->Bios.MaxSector) + 1;
 | |
|     Temp      = ShortLba / BiosBlockIoDev->Bios.MaxSector;
 | |
|     Head      = Temp % (BiosBlockIoDev->Bios.MaxHead + 1);
 | |
|     Cylinder  = Temp / (BiosBlockIoDev->Bios.MaxHead + 1);
 | |
| 
 | |
|     //
 | |
|     // Limit transfer to this Head & Cylinder
 | |
|     //
 | |
|     NumberOfBlocks  = BufferSize / BlockSize;
 | |
|     Temp            = BiosBlockIoDev->Bios.MaxSector - Sector + 1;
 | |
|     NumberOfBlocks  = NumberOfBlocks > Temp ? Temp : NumberOfBlocks;
 | |
| 
 | |
|     Retry           = 3;
 | |
|     do {
 | |
|       //
 | |
|       // Perform the IO
 | |
|       //
 | |
|       Regs.H.AH     = 2;
 | |
|       Regs.H.AL     = (UINT8) NumberOfBlocks;
 | |
|       Regs.H.DL     = BiosBlockIoDev->Bios.Number;
 | |
| 
 | |
|       UpperCylinder = (Cylinder & 0x0f00) >> 2;
 | |
| 
 | |
|       CheckLba      = Cylinder * (BiosBlockIoDev->Bios.MaxHead + 1) + Head;
 | |
|       CheckLba      = CheckLba * BiosBlockIoDev->Bios.MaxSector + Sector - 1;
 | |
| 
 | |
|       DEBUG (
 | |
|         (DEBUG_BLKIO,
 | |
|         "RLD: LBA %x (%x), Sector %x (%x), Head %x (%x), Cyl %x, UCyl %x\n",
 | |
|         ShortLba,
 | |
|         CheckLba,
 | |
|         Sector,
 | |
|         BiosBlockIoDev->Bios.MaxSector,
 | |
|         Head,
 | |
|         BiosBlockIoDev->Bios.MaxHead,
 | |
|         Cylinder,
 | |
|         UpperCylinder)
 | |
|         );
 | |
|       ASSERT (CheckLba == ShortLba);
 | |
| 
 | |
|       Regs.H.CL = (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff));
 | |
|       Regs.H.DH = (UINT8) (Head & 0x3f);
 | |
|       Regs.H.CH = (UINT8) (Cylinder & 0xff);
 | |
| 
 | |
|       Regs.X.BX = EFI_OFFSET (mEdd11Buffer);
 | |
|       Regs.X.ES = EFI_SEGMENT (mEdd11Buffer);
 | |
| 
 | |
|       DEBUG (
 | |
|         (DEBUG_BLKIO,
 | |
|         "INT 13h: AX:(02%02x) DX:(%02x%02x) CX:(%02x%02x) BX:(%04x) ES:(%04x)\n",
 | |
|         Regs.H.AL,
 | |
|         (UINT8) (Head & 0x3f),
 | |
|         Regs.H.DL,
 | |
|         (UINT8) (Cylinder & 0xff),
 | |
|         (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff)),
 | |
|         EFI_OFFSET (mEdd11Buffer),
 | |
|         EFI_SEGMENT (mEdd11Buffer))
 | |
|         );
 | |
| 
 | |
|       CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
 | |
|       DEBUG (
 | |
|         (
 | |
|         DEBUG_BLKIO, "BiosReadLegacyDrive: INT 13 02 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number,
 | |
|         CarryFlag, Regs.H.AH
 | |
|         )
 | |
|         );
 | |
|       Retry--;
 | |
|     } while (CarryFlag != 0 && Retry != 0 && Regs.H.AH != BIOS_DISK_CHANGED);
 | |
| 
 | |
|     Media->MediaPresent = TRUE;
 | |
|     if (CarryFlag != 0) {
 | |
|       //
 | |
|       // Return Error Status
 | |
|       //
 | |
|       BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
 | |
|       if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
 | |
|         Media->MediaId++;
 | |
|         Bios = &BiosBlockIoDev->Bios;
 | |
|         if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
 | |
|           //
 | |
|           // If the size of the media changed we need to reset the disk geometry
 | |
|           //
 | |
|           if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
 | |
|             Media->LastBlock  = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
 | |
|             Media->BlockSize  = (UINT32) Bios->Parameters.BytesPerSector;
 | |
|           } else {
 | |
|             //
 | |
|             // Legacy Interfaces
 | |
|             //
 | |
|             Media->LastBlock  = (Bios->MaxHead + 1) * Bios->MaxSector * (Bios->MaxCylinder + 1) - 1;
 | |
|             Media->BlockSize  = 512;
 | |
|           }
 | |
| 
 | |
|           Media->ReadOnly = FALSE;
 | |
|           gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
 | |
|           gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
 | |
|           return EFI_MEDIA_CHANGED;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (Media->RemovableMedia) {
 | |
|         Media->MediaPresent = FALSE;
 | |
|       }
 | |
| 
 | |
|       return EFI_DEVICE_ERROR;
 | |
|     }
 | |
| 
 | |
|     TransferByteSize = NumberOfBlocks * BlockSize;
 | |
|     CopyMem (Buffer, mEdd11Buffer, TransferByteSize);
 | |
| 
 | |
|     ShortLba    = ShortLba + NumberOfBlocks;
 | |
|     BufferSize  = BufferSize - TransferByteSize;
 | |
|     Buffer      = (VOID *) ((UINT8 *) Buffer + TransferByteSize);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Write BufferSize bytes from Lba into Buffer.
 | |
| 
 | |
|   @param  This       Indicates a pointer to the calling context.
 | |
|   @param  MediaId    The media ID that the write request is for.
 | |
|   @param  Lba        The starting logical block address to be written. The caller is
 | |
|                      responsible for writing to only legitimate locations.
 | |
|   @param  BufferSize Size of Buffer, must be a multiple of device block size.
 | |
|   @param  Buffer     A pointer to the source buffer for the data.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The data was written correctly to the device.
 | |
|   @retval EFI_WRITE_PROTECTED   The device can not be written to.
 | |
|   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
 | |
|   @retval EFI_NO_MEDIA          There is no media in the device.
 | |
|   @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
 | |
|   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
 | |
|   @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, 
 | |
|                                 or the buffer is not on proper alignment.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| BiosWriteLegacyDrive (
 | |
|   IN  EFI_BLOCK_IO_PROTOCOL *This,
 | |
|   IN  UINT32                MediaId,
 | |
|   IN  EFI_LBA               Lba,
 | |
|   IN  UINTN                 BufferSize,
 | |
|   OUT VOID                  *Buffer
 | |
|   )
 | |
| {
 | |
|   EFI_BLOCK_IO_MEDIA    *Media;
 | |
|   BIOS_BLOCK_IO_DEV     *BiosBlockIoDev;
 | |
|   EFI_IA32_REGISTER_SET Regs;
 | |
|   UINTN                 UpperCylinder;
 | |
|   UINTN                 Temp;
 | |
|   UINTN                 Cylinder;
 | |
|   UINTN                 Head;
 | |
|   UINTN                 Sector;
 | |
|   UINTN                 NumberOfBlocks;
 | |
|   UINTN                 TransferByteSize;
 | |
|   UINTN                 ShortLba;
 | |
|   UINTN                 CheckLba;
 | |
|   UINTN                 BlockSize;
 | |
|   BIOS_LEGACY_DRIVE     *Bios;
 | |
|   UINTN                 CarryFlag;
 | |
|   UINTN                 Retry;
 | |
|   EFI_BLOCK_IO_PROTOCOL *BlockIo;
 | |
| 
 | |
|   Media     = This->Media;
 | |
|   BlockSize = Media->BlockSize;
 | |
| 
 | |
|   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
 | |
| 
 | |
|   if (MediaId != Media->MediaId) {
 | |
|     return EFI_MEDIA_CHANGED;
 | |
|   }
 | |
| 
 | |
|   if (Lba > Media->LastBlock) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (BufferSize % BlockSize != 0) {
 | |
|     return EFI_BAD_BUFFER_SIZE;
 | |
|   }
 | |
| 
 | |
|   if (Buffer == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (BufferSize == 0) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   BiosBlockIoDev  = BIOS_BLOCK_IO_FROM_THIS (This);
 | |
|   ShortLba        = (UINTN) Lba;
 | |
| 
 | |
|   while (BufferSize != 0) {
 | |
|     //
 | |
|     // Compute I/O location in Sector, Head, Cylinder format
 | |
|     //
 | |
|     Sector    = (ShortLba % BiosBlockIoDev->Bios.MaxSector) + 1;
 | |
|     Temp      = ShortLba / BiosBlockIoDev->Bios.MaxSector;
 | |
|     Head      = Temp % (BiosBlockIoDev->Bios.MaxHead + 1);
 | |
|     Cylinder  = Temp / (BiosBlockIoDev->Bios.MaxHead + 1);
 | |
| 
 | |
|     //
 | |
|     // Limit transfer to this Head & Cylinder
 | |
|     //
 | |
|     NumberOfBlocks  = BufferSize / BlockSize;
 | |
|     Temp            = BiosBlockIoDev->Bios.MaxSector - Sector + 1;
 | |
|     NumberOfBlocks  = NumberOfBlocks > Temp ? Temp : NumberOfBlocks;
 | |
| 
 | |
|     Retry           = 3;
 | |
|     do {
 | |
|       //
 | |
|       // Perform the IO
 | |
|       //
 | |
|       Regs.H.AH     = 3;
 | |
|       Regs.H.AL     = (UINT8) NumberOfBlocks;
 | |
|       Regs.H.DL     = BiosBlockIoDev->Bios.Number;
 | |
| 
 | |
|       UpperCylinder = (Cylinder & 0x0f00) >> 2;
 | |
| 
 | |
|       CheckLba      = Cylinder * (BiosBlockIoDev->Bios.MaxHead + 1) + Head;
 | |
|       CheckLba      = CheckLba * BiosBlockIoDev->Bios.MaxSector + Sector - 1;
 | |
| 
 | |
|       DEBUG (
 | |
|         (DEBUG_BLKIO,
 | |
|         "RLD: LBA %x (%x), Sector %x (%x), Head %x (%x), Cyl %x, UCyl %x\n",
 | |
|         ShortLba,
 | |
|         CheckLba,
 | |
|         Sector,
 | |
|         BiosBlockIoDev->Bios.MaxSector,
 | |
|         Head,
 | |
|         BiosBlockIoDev->Bios.MaxHead,
 | |
|         Cylinder,
 | |
|         UpperCylinder)
 | |
|         );
 | |
|       ASSERT (CheckLba == ShortLba);
 | |
| 
 | |
|       Regs.H.CL         = (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff));
 | |
|       Regs.H.DH         = (UINT8) (Head & 0x3f);
 | |
|       Regs.H.CH         = (UINT8) (Cylinder & 0xff);
 | |
| 
 | |
|       Regs.X.BX         = EFI_OFFSET (mEdd11Buffer);
 | |
|       Regs.X.ES         = EFI_SEGMENT (mEdd11Buffer);
 | |
| 
 | |
|       TransferByteSize  = NumberOfBlocks * BlockSize;
 | |
|       CopyMem (mEdd11Buffer, Buffer, TransferByteSize);
 | |
| 
 | |
|       DEBUG (
 | |
|         (DEBUG_BLKIO,
 | |
|         "INT 13h: AX:(03%02x) DX:(%02x%02x) CX:(%02x%02x) BX:(%04x) ES:(%04x)\n",
 | |
|         Regs.H.AL,
 | |
|         (UINT8) (Head & 0x3f),
 | |
|         Regs.H.DL,
 | |
|         (UINT8) (Cylinder & 0xff),
 | |
|         (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff)),
 | |
|         EFI_OFFSET (mEdd11Buffer),
 | |
|         EFI_SEGMENT (mEdd11Buffer))
 | |
|         );
 | |
| 
 | |
|       CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
 | |
|       DEBUG (
 | |
|         (
 | |
|         DEBUG_BLKIO, "BiosWriteLegacyDrive: INT 13 03 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number,
 | |
|         CarryFlag, Regs.H.AH
 | |
|         )
 | |
|         );
 | |
|       Retry--;
 | |
|     } while (CarryFlag != 0 && Retry != 0 && Regs.H.AH != BIOS_DISK_CHANGED);
 | |
| 
 | |
|     Media->MediaPresent = TRUE;
 | |
|     if (CarryFlag != 0) {
 | |
|       //
 | |
|       // Return Error Status
 | |
|       //
 | |
|       BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
 | |
|       if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
 | |
|         Media->MediaId++;
 | |
|         Bios = &BiosBlockIoDev->Bios;
 | |
|         if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
 | |
|           if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
 | |
|             Media->LastBlock  = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
 | |
|             Media->BlockSize  = (UINT32) Bios->Parameters.BytesPerSector;
 | |
|           } else {
 | |
|             //
 | |
|             // Legacy Interfaces
 | |
|             //
 | |
|             Media->LastBlock  = (Bios->MaxHead + 1) * Bios->MaxSector * (Bios->MaxCylinder + 1) - 1;
 | |
|             Media->BlockSize  = 512;
 | |
|           }
 | |
|           //
 | |
|           // If the size of the media changed we need to reset the disk geometry
 | |
|           //
 | |
|           Media->ReadOnly = FALSE;
 | |
|           gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
 | |
|           gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
 | |
|           return EFI_MEDIA_CHANGED;
 | |
|         }
 | |
|       } else if (BiosBlockIoDev->Bios.ErrorCode == BIOS_WRITE_PROTECTED) {
 | |
|         Media->ReadOnly = TRUE;
 | |
|         return EFI_WRITE_PROTECTED;
 | |
|       }
 | |
| 
 | |
|       if (Media->RemovableMedia) {
 | |
|         Media->MediaPresent = FALSE;
 | |
|       }
 | |
| 
 | |
|       return EFI_DEVICE_ERROR;
 | |
|     }
 | |
| 
 | |
|     Media->ReadOnly = FALSE;
 | |
|     ShortLba        = ShortLba + NumberOfBlocks;
 | |
|     BufferSize      = BufferSize - TransferByteSize;
 | |
|     Buffer          = (VOID *) ((UINT8 *) Buffer + TransferByteSize);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 |