Home | History | Annotate | Download | only in BlockIoDxe
      1 /** @file
      2   Routines that use BIOS to support INT 13 devices.
      3 
      4 Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
      5 
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions
      8 of the BSD License which accompanies this distribution.  The
      9 full text of the license may be found at
     10 http://opensource.org/licenses/bsd-license.php
     11 
     12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include "BiosBlkIo.h"
     18 
     19 //
     20 // Module global variables
     21 //
     22 //
     23 // Address packet is a buffer under 1 MB for all version EDD calls
     24 //
     25 extern EDD_DEVICE_ADDRESS_PACKET  *mEddBufferUnder1Mb;
     26 
     27 //
     28 // This is a buffer for INT 13h func 48 information
     29 //
     30 extern BIOS_LEGACY_DRIVE          *mLegacyDriverUnder1Mb;
     31 
     32 //
     33 // Buffer of 0xFE00 bytes for EDD 1.1 transfer must be under 1 MB
     34 //  0xFE00 bytes is the max transfer size supported.
     35 //
     36 extern VOID                       *mEdd11Buffer;
     37 
     38 
     39 /**
     40   Initialize block I/O device instance
     41 
     42   @param  Dev   Instance of block I/O device instance
     43 
     44   @retval TRUE  Initialization succeeds.
     45   @retval FALSE Initialization fails.
     46 
     47 **/
     48 BOOLEAN
     49 BiosInitBlockIo (
     50   IN  BIOS_BLOCK_IO_DEV         *Dev
     51   )
     52 {
     53   EFI_BLOCK_IO_PROTOCOL *BlockIo;
     54   EFI_BLOCK_IO_MEDIA    *BlockMedia;
     55   BIOS_LEGACY_DRIVE     *Bios;
     56 
     57   BlockIo         = &Dev->BlockIo;
     58   BlockIo->Media  = &Dev->BlockMedia;
     59   BlockMedia      = BlockIo->Media;
     60   Bios            = &Dev->Bios;
     61 
     62   if (Int13GetDeviceParameters (Dev, Bios) != 0) {
     63     if (Int13Extensions (Dev, Bios) != 0) {
     64       BlockMedia->LastBlock = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
     65       BlockMedia->BlockSize = (UINT32) Bios->Parameters.BytesPerSector;
     66 
     67       if ((Bios->Parameters.Flags & EDD_DEVICE_REMOVABLE) == EDD_DEVICE_REMOVABLE) {
     68         BlockMedia->RemovableMedia = TRUE;
     69       }
     70 
     71     } else {
     72       //
     73       // Legacy Interfaces
     74       //
     75       BlockMedia->BlockSize = 512;
     76       BlockMedia->LastBlock = (Bios->MaxHead + 1) * Bios->MaxSector * (Bios->MaxCylinder + 1) - 1;
     77     }
     78 
     79     DEBUG ((DEBUG_INIT, "BlockSize = %d  LastBlock = %d\n", BlockMedia->BlockSize, BlockMedia->LastBlock));
     80 
     81     BlockMedia->LogicalPartition  = FALSE;
     82     BlockMedia->WriteCaching      = FALSE;
     83 
     84     //
     85     // BugBug: Need to set this for removable media devices if they do not
     86     //  have media present
     87     //
     88     BlockMedia->ReadOnly      = FALSE;
     89     BlockMedia->MediaPresent  = TRUE;
     90 
     91     BlockIo->Reset            = BiosBlockIoReset;
     92     BlockIo->FlushBlocks      = BiosBlockIoFlushBlocks;
     93 
     94     if (!Bios->ExtendedInt13) {
     95       //
     96       // Legacy interfaces
     97       //
     98       BlockIo->ReadBlocks   = BiosReadLegacyDrive;
     99       BlockIo->WriteBlocks  = BiosWriteLegacyDrive;
    100     } else if ((Bios->EddVersion == EDD_VERSION_30) && (Bios->Extensions64Bit)) {
    101       //
    102       // EDD 3.0 Required for Device path, but extended reads are not required.
    103       //
    104       BlockIo->ReadBlocks   = Edd30BiosReadBlocks;
    105       BlockIo->WriteBlocks  = Edd30BiosWriteBlocks;
    106     } else {
    107       //
    108       // Assume EDD 1.1 - Read and Write functions.
    109       //  This could be EDD 3.0 without Extensions64Bit being set.
    110       // If it's EDD 1.1 this will work, but the device path will not
    111       //  be correct. This will cause confusion to EFI OS installation.
    112       //
    113       BlockIo->ReadBlocks   = Edd11BiosReadBlocks;
    114       BlockIo->WriteBlocks  = Edd11BiosWriteBlocks;
    115     }
    116 
    117     BlockMedia->LogicalPartition  = FALSE;
    118     BlockMedia->WriteCaching      = FALSE;
    119 
    120     return TRUE;
    121   }
    122 
    123   return FALSE;
    124 }
    125 
    126 /**
    127   Gets parameters of block I/O device.
    128 
    129   @param  BiosBlockIoDev Instance of block I/O device.
    130   @param  Drive          Legacy drive.
    131 
    132   @return  Result of device parameter retrieval.
    133 
    134 **/
    135 UINTN
    136 Int13GetDeviceParameters (
    137   IN  BIOS_BLOCK_IO_DEV    *BiosBlockIoDev,
    138   IN  BIOS_LEGACY_DRIVE    *Drive
    139   )
    140 {
    141   UINTN                 CarryFlag;
    142   UINT16                Cylinder;
    143   EFI_IA32_REGISTER_SET Regs;
    144 
    145   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
    146 
    147   Regs.H.AH = 0x08;
    148   Regs.H.DL = Drive->Number;
    149   CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
    150   DEBUG ((DEBUG_INIT, "Int13GetDeviceParameters: INT 13 08 DL=%02x : CF=%d AH=%02x\n", Drive->Number, CarryFlag, Regs.H.AH));
    151   if (CarryFlag != 0 || Regs.H.AH != 0x00) {
    152     Drive->ErrorCode = Regs.H.AH;
    153     return FALSE;
    154   }
    155 
    156   if (Drive->Floppy) {
    157     if (Regs.H.BL == 0x10) {
    158       Drive->AtapiFloppy = TRUE;
    159     } else {
    160       Drive->MaxHead      = Regs.H.DH;
    161       Drive->MaxSector    = Regs.H.CL;
    162       Drive->MaxCylinder  = Regs.H.CH;
    163       if (Drive->MaxSector == 0) {
    164         //
    165         // BugBug: You can not trust the Carry flag.
    166         //
    167         return FALSE;
    168       }
    169     }
    170   } else {
    171     Drive->MaxHead  = (UINT8) (Regs.H.DH & 0x3f);
    172     Cylinder        = (UINT16) (((UINT16) Regs.H.DH & 0xc0) << 4);
    173     Cylinder        = (UINT16) (Cylinder | ((UINT16) Regs.H.CL & 0xc0) << 2);
    174     Drive->MaxCylinder  = (UINT16) (Cylinder + Regs.H.CH);
    175     Drive->MaxSector    = (UINT8) (Regs.H.CL & 0x3f);
    176   }
    177 
    178   return TRUE;
    179 }
    180 
    181 /**
    182   Extension of INT13 call.
    183 
    184   @param  BiosBlockIoDev Instance of block I/O device.
    185   @param  Drive          Legacy drive.
    186 
    187   @return  Result of this extension.
    188 
    189 **/
    190 UINTN
    191 Int13Extensions (
    192   IN  BIOS_BLOCK_IO_DEV    *BiosBlockIoDev,
    193   IN  BIOS_LEGACY_DRIVE    *Drive
    194   )
    195 {
    196   INTN                  CarryFlag;
    197   EFI_IA32_REGISTER_SET Regs;
    198 
    199   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
    200 
    201   Regs.H.AH = 0x41;
    202   Regs.X.BX = 0x55aa;
    203   Regs.H.DL = Drive->Number;
    204   CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
    205   DEBUG ((DEBUG_INIT, "Int13Extensions: INT 13 41 DL=%02x : CF=%d BX=%04x\n", Drive->Number, CarryFlag, Regs.X.BX));
    206   if (CarryFlag != 0 || Regs.X.BX != 0xaa55) {
    207     Drive->ExtendedInt13            = FALSE;
    208     Drive->DriveLockingAndEjecting  = FALSE;
    209     Drive->Edd                      = FALSE;
    210     return FALSE;
    211   }
    212 
    213   Drive->EddVersion               = Regs.H.AH;
    214   Drive->ExtendedInt13            = (BOOLEAN) ((Regs.X.CX & 0x01) == 0x01);
    215   Drive->DriveLockingAndEjecting  = (BOOLEAN) ((Regs.X.CX & 0x02) == 0x02);
    216   Drive->Edd                      = (BOOLEAN) ((Regs.X.CX & 0x04) == 0x04);
    217   Drive->Extensions64Bit          = (BOOLEAN) (Regs.X.CX & 0x08);
    218 
    219   Drive->ParametersValid          = (UINT8) GetDriveParameters (BiosBlockIoDev, Drive);
    220   return TRUE;
    221 }
    222 
    223 /**
    224   Gets parameters of legacy drive.
    225 
    226   @param  BiosBlockIoDev Instance of block I/O device.
    227   @param  Drive          Legacy drive.
    228 
    229   @return  Result of drive parameter retrieval.
    230 
    231 **/
    232 UINTN
    233 GetDriveParameters (
    234   IN  BIOS_BLOCK_IO_DEV   *BiosBlockIoDev,
    235   IN  BIOS_LEGACY_DRIVE   *Drive
    236   )
    237 {
    238   INTN                  CarryFlag;
    239   EFI_IA32_REGISTER_SET Regs;
    240   UINTN                 PointerMath;
    241 
    242   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
    243 
    244   Regs.H.AH = 0x48;
    245   Regs.H.DL = Drive->Number;
    246 
    247   //
    248   // EDD Buffer must be passed in with max buffer size as first entry in the buffer
    249   //
    250   mLegacyDriverUnder1Mb->Parameters.StructureSize = (UINT16) sizeof (EDD_DRIVE_PARAMETERS);
    251   Regs.X.DS = EFI_SEGMENT ((UINTN)(&mLegacyDriverUnder1Mb->Parameters));
    252   Regs.X.SI = EFI_OFFSET ((UINTN)(&mLegacyDriverUnder1Mb->Parameters));
    253   CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
    254   DEBUG ((DEBUG_INIT, "GetDriveParameters: INT 13 48 DL=%02x : CF=%d AH=%02x\n", Drive->Number, CarryFlag, Regs.H.AH));
    255   if (CarryFlag != 0 || Regs.H.AH != 0x00) {
    256     Drive->ErrorCode = Regs.H.AH;
    257     SetMem (&Drive->Parameters, sizeof (Drive->Parameters), 0xaf);
    258     return FALSE;
    259   }
    260   //
    261   // We only have one buffer < 1MB, so copy into our instance data
    262   //
    263   CopyMem (
    264     &Drive->Parameters,
    265     &mLegacyDriverUnder1Mb->Parameters,
    266     sizeof (Drive->Parameters)
    267     );
    268 
    269   if (Drive->AtapiFloppy) {
    270     //
    271     // Sense Media Type
    272     //
    273     Regs.H.AH = 0x20;
    274     Regs.H.DL = Drive->Number;
    275     CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
    276     DEBUG ((DEBUG_INIT, "GetDriveParameters: INT 13 20 DL=%02x : CF=%d AL=%02x\n", Drive->Number, CarryFlag, Regs.H.AL));
    277     if (CarryFlag != 0) {
    278       //
    279       // Media not present or unknown media present
    280       //
    281       if ((Drive->Parameters.Flags & EDD_GEOMETRY_VALID) == EDD_GEOMETRY_VALID) {
    282         Drive->MaxHead    = (UINT8) (Drive->Parameters.MaxHeads - 1);
    283         Drive->MaxSector  = (UINT8) Drive->Parameters.SectorsPerTrack;
    284         ASSERT (Drive->MaxSector != 0);
    285         Drive->MaxCylinder = (UINT16) (Drive->Parameters.MaxCylinders - 1);
    286       } else {
    287         Drive->MaxHead      = 0;
    288         Drive->MaxSector    = 1;
    289         Drive->MaxCylinder  = 0;
    290       }
    291 
    292     } else {
    293       //
    294       // Media Present
    295       //
    296       switch (Regs.H.AL) {
    297       case 0x03:
    298         //
    299         // 720 KB
    300         //
    301         Drive->MaxHead      = 1;
    302         Drive->MaxSector    = 9;
    303         Drive->MaxCylinder  = 79;
    304         break;
    305 
    306       case 0x04:
    307         //
    308         // 1.44MB
    309         //
    310         Drive->MaxHead      = 1;
    311         Drive->MaxSector    = 18;
    312         Drive->MaxCylinder  = 79;
    313         break;
    314 
    315       case 0x06:
    316         //
    317         // 2.88MB
    318         //
    319         Drive->MaxHead      = 1;
    320         Drive->MaxSector    = 36;
    321         Drive->MaxCylinder  = 79;
    322         break;
    323 
    324       case 0x0C:
    325         //
    326         // 360 KB
    327         //
    328         Drive->MaxHead      = 1;
    329         Drive->MaxSector    = 9;
    330         Drive->MaxCylinder  = 39;
    331         break;
    332 
    333       case 0x0D:
    334         //
    335         // 1.2 MB
    336         //
    337         Drive->MaxHead      = 1;
    338         Drive->MaxSector    = 15;
    339         Drive->MaxCylinder  = 79;
    340         break;
    341 
    342       case 0x0E:
    343         //
    344         // Toshiba 3 mode
    345         //
    346       case 0x0F:
    347         //
    348         // NEC 3 mode
    349         //
    350       case 0x10:
    351         //
    352         // Default Media
    353         //
    354         if ((Drive->Parameters.Flags & EDD_GEOMETRY_VALID) == EDD_GEOMETRY_VALID) {
    355           Drive->MaxHead    = (UINT8) (Drive->Parameters.MaxHeads - 1);
    356           Drive->MaxSector  = (UINT8) Drive->Parameters.SectorsPerTrack;
    357           ASSERT (Drive->MaxSector != 0);
    358           Drive->MaxCylinder = (UINT16) (Drive->Parameters.MaxCylinders - 1);
    359         } else {
    360           Drive->MaxHead      = 0;
    361           Drive->MaxSector    = 1;
    362           Drive->MaxCylinder  = 0;
    363         }
    364         break;
    365 
    366       default:
    367         //
    368         // Unknown media type.
    369         //
    370         Drive->MaxHead      = 0;
    371         Drive->MaxSector    = 1;
    372         Drive->MaxCylinder  = 0;
    373         break;
    374       }
    375     }
    376 
    377     Drive->Parameters.PhysicalSectors = (Drive->MaxHead + 1) * Drive->MaxSector * (Drive->MaxCylinder + 1);
    378     Drive->Parameters.BytesPerSector  = 512;
    379   }
    380   //
    381   // This data comes from the BIOS so it may not allways be valid
    382   //  since the BIOS may reuse this buffer for future accesses
    383   //
    384   PointerMath = EFI_SEGMENT (Drive->Parameters.Fdpt) << 4;
    385   PointerMath += EFI_OFFSET (Drive->Parameters.Fdpt);
    386   Drive->FdptPointer = (VOID *) PointerMath;
    387 
    388   return TRUE;
    389 }
    390 //
    391 // Block IO Routines
    392 //
    393 
    394 /**
    395   Read BufferSize bytes from Lba into Buffer.
    396 
    397   @param  This       Indicates a pointer to the calling context.
    398   @param  MediaId    Id of the media, changes every time the media is replaced.
    399   @param  Lba        The starting Logical Block Address to read from
    400   @param  BufferSize Size of Buffer, must be a multiple of device block size.
    401   @param  Buffer     A pointer to the destination buffer for the data. The caller is
    402                      responsible for either having implicit or explicit ownership of the buffer.
    403 
    404   @retval EFI_SUCCESS           The data was read correctly from the device.
    405   @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.
    406   @retval EFI_NO_MEDIA          There is no media in the device.
    407   @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.
    408   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
    409   @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
    410                                 or the buffer is not on proper alignment.
    411 
    412 **/
    413 EFI_STATUS
    414 EFIAPI
    415 Edd30BiosReadBlocks (
    416   IN  EFI_BLOCK_IO_PROTOCOL *This,
    417   IN  UINT32                MediaId,
    418   IN  EFI_LBA               Lba,
    419   IN  UINTN                 BufferSize,
    420   OUT VOID                  *Buffer
    421   )
    422 {
    423   EFI_BLOCK_IO_MEDIA        *Media;
    424   BIOS_BLOCK_IO_DEV         *BiosBlockIoDev;
    425   EDD_DEVICE_ADDRESS_PACKET *AddressPacket;
    426   //
    427   // I exist only for readability
    428   //
    429   EFI_IA32_REGISTER_SET     Regs;
    430   UINT64                    TransferBuffer;
    431   UINTN                     NumberOfBlocks;
    432   UINTN                     TransferByteSize;
    433   UINTN                     BlockSize;
    434   BIOS_LEGACY_DRIVE         *Bios;
    435   UINTN                     CarryFlag;
    436   UINTN                     MaxTransferBlocks;
    437   EFI_BLOCK_IO_PROTOCOL     *BlockIo;
    438 
    439   Media     = This->Media;
    440   BlockSize = Media->BlockSize;
    441 
    442   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
    443 
    444   if (MediaId != Media->MediaId) {
    445     return EFI_MEDIA_CHANGED;
    446   }
    447 
    448   if (Lba > Media->LastBlock) {
    449     return EFI_INVALID_PARAMETER;
    450   }
    451 
    452   if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
    453     return EFI_INVALID_PARAMETER;
    454   }
    455 
    456   if (BufferSize % BlockSize != 0) {
    457     return EFI_BAD_BUFFER_SIZE;
    458   }
    459 
    460   if (Buffer == NULL) {
    461     return EFI_INVALID_PARAMETER;
    462   }
    463 
    464   if (BufferSize == 0) {
    465     return EFI_SUCCESS;
    466   }
    467 
    468   BiosBlockIoDev    = BIOS_BLOCK_IO_FROM_THIS (This);
    469   AddressPacket     = mEddBufferUnder1Mb;
    470 
    471   MaxTransferBlocks = MAX_EDD11_XFER / BlockSize;
    472 
    473   TransferBuffer    = (UINT64)(UINTN) Buffer;
    474   for (; BufferSize > 0;) {
    475     NumberOfBlocks  = BufferSize / BlockSize;
    476     NumberOfBlocks  = NumberOfBlocks > MaxTransferBlocks ? MaxTransferBlocks : NumberOfBlocks;
    477     //
    478     // Max transfer MaxTransferBlocks
    479     //
    480     AddressPacket->PacketSizeInBytes  = (UINT8) sizeof (EDD_DEVICE_ADDRESS_PACKET);
    481     AddressPacket->Zero               = 0;
    482     AddressPacket->NumberOfBlocks     = (UINT8) NumberOfBlocks;
    483     AddressPacket->Zero2              = 0;
    484     AddressPacket->SegOffset          = 0xffffffff;
    485     AddressPacket->Lba                = (UINT64) Lba;
    486     AddressPacket->TransferBuffer     = TransferBuffer;
    487 
    488     Regs.H.AH                         = 0x42;
    489     Regs.H.DL                         = BiosBlockIoDev->Bios.Number;
    490     Regs.X.SI                         = EFI_OFFSET (AddressPacket);
    491     Regs.X.DS                         = EFI_SEGMENT (AddressPacket);
    492 
    493     CarryFlag                         = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
    494     DEBUG (
    495       (
    496       DEBUG_BLKIO, "Edd30BiosReadBlocks: INT 13 42 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number,
    497       CarryFlag, Regs.H.AH
    498       )
    499       );
    500 
    501     Media->MediaPresent = TRUE;
    502     if (CarryFlag != 0) {
    503       //
    504       // Return Error Status
    505       //
    506       BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
    507       if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
    508         Media->MediaId++;
    509         Bios = &BiosBlockIoDev->Bios;
    510         if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
    511           if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
    512             Media->LastBlock  = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
    513             Media->BlockSize  = (UINT32) Bios->Parameters.BytesPerSector;
    514           } else {
    515             ASSERT (FALSE);
    516           }
    517 
    518           Media->ReadOnly = FALSE;
    519           gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
    520           gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
    521           return EFI_MEDIA_CHANGED;
    522         }
    523       }
    524 
    525       if (Media->RemovableMedia) {
    526         Media->MediaPresent = FALSE;
    527       }
    528 
    529       return EFI_DEVICE_ERROR;
    530     }
    531 
    532     TransferByteSize  = NumberOfBlocks * BlockSize;
    533     BufferSize        = BufferSize - TransferByteSize;
    534     TransferBuffer += TransferByteSize;
    535     Lba += NumberOfBlocks;
    536   }
    537 
    538   return EFI_SUCCESS;
    539 }
    540 
    541 /**
    542   Write BufferSize bytes from Lba into Buffer.
    543 
    544   @param  This       Indicates a pointer to the calling context.
    545   @param  MediaId    The media ID that the write request is for.
    546   @param  Lba        The starting logical block address to be written. The caller is
    547                      responsible for writing to only legitimate locations.
    548   @param  BufferSize Size of Buffer, must be a multiple of device block size.
    549   @param  Buffer     A pointer to the source buffer for the data.
    550 
    551   @retval EFI_SUCCESS           The data was written correctly to the device.
    552   @retval EFI_WRITE_PROTECTED   The device can not be written to.
    553   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
    554   @retval EFI_NO_MEDIA          There is no media in the device.
    555   @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
    556   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
    557   @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
    558                                 or the buffer is not on proper alignment.
    559 
    560 **/
    561 EFI_STATUS
    562 EFIAPI
    563 Edd30BiosWriteBlocks (
    564   IN  EFI_BLOCK_IO_PROTOCOL *This,
    565   IN  UINT32                MediaId,
    566   IN  EFI_LBA               Lba,
    567   IN  UINTN                 BufferSize,
    568   OUT VOID                  *Buffer
    569   )
    570 {
    571   EFI_BLOCK_IO_MEDIA        *Media;
    572   BIOS_BLOCK_IO_DEV         *BiosBlockIoDev;
    573   EDD_DEVICE_ADDRESS_PACKET *AddressPacket;
    574   //
    575   // I exist only for readability
    576   //
    577   EFI_IA32_REGISTER_SET     Regs;
    578   UINT64                    TransferBuffer;
    579   UINTN                     NumberOfBlocks;
    580   UINTN                     TransferByteSize;
    581   UINTN                     BlockSize;
    582   BIOS_LEGACY_DRIVE         *Bios;
    583   UINTN                     CarryFlag;
    584   UINTN                     MaxTransferBlocks;
    585   EFI_BLOCK_IO_PROTOCOL     *BlockIo;
    586 
    587   Media     = This->Media;
    588   BlockSize = Media->BlockSize;
    589 
    590   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
    591 
    592   if (MediaId != Media->MediaId) {
    593     return EFI_MEDIA_CHANGED;
    594   }
    595 
    596   if (Lba > Media->LastBlock) {
    597     return EFI_DEVICE_ERROR;
    598   }
    599 
    600   if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
    601     return EFI_INVALID_PARAMETER;
    602   }
    603 
    604   if (BufferSize % BlockSize != 0) {
    605     return EFI_BAD_BUFFER_SIZE;
    606   }
    607 
    608   if (Buffer == NULL) {
    609     return EFI_INVALID_PARAMETER;
    610   }
    611 
    612   if (BufferSize == 0) {
    613     return EFI_SUCCESS;
    614   }
    615 
    616   BiosBlockIoDev    = BIOS_BLOCK_IO_FROM_THIS (This);
    617   AddressPacket     = mEddBufferUnder1Mb;
    618 
    619   MaxTransferBlocks = MAX_EDD11_XFER / BlockSize;
    620 
    621   TransferBuffer    = (UINT64)(UINTN) Buffer;
    622   for (; BufferSize > 0;) {
    623     NumberOfBlocks  = BufferSize / BlockSize;
    624     NumberOfBlocks  = NumberOfBlocks > MaxTransferBlocks ? MaxTransferBlocks : NumberOfBlocks;
    625     //
    626     // Max transfer MaxTransferBlocks
    627     //
    628     AddressPacket->PacketSizeInBytes  = (UINT8) sizeof (EDD_DEVICE_ADDRESS_PACKET);
    629     AddressPacket->Zero               = 0;
    630     AddressPacket->NumberOfBlocks     = (UINT8) NumberOfBlocks;
    631     AddressPacket->Zero2              = 0;
    632     AddressPacket->SegOffset          = 0xffffffff;
    633     AddressPacket->Lba                = (UINT64) Lba;
    634     AddressPacket->TransferBuffer     = TransferBuffer;
    635 
    636     Regs.H.AH                         = 0x43;
    637     Regs.H.AL                         = 0x00;
    638     //
    639     // Write Verify Off
    640     //
    641     Regs.H.DL = (UINT8) (BiosBlockIoDev->Bios.Number);
    642     Regs.X.SI = EFI_OFFSET (AddressPacket);
    643     Regs.X.DS = EFI_SEGMENT (AddressPacket);
    644 
    645     CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
    646     DEBUG (
    647       (
    648       DEBUG_BLKIO, "Edd30BiosWriteBlocks: INT 13 43 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number,
    649       CarryFlag, Regs.H.AH
    650       )
    651       );
    652 
    653     Media->MediaPresent = TRUE;
    654     if (CarryFlag != 0) {
    655       //
    656       // Return Error Status
    657       //
    658       BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
    659       if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
    660         Media->MediaId++;
    661         Bios = &BiosBlockIoDev->Bios;
    662         if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
    663           if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
    664             Media->LastBlock  = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
    665             Media->BlockSize  = (UINT32) Bios->Parameters.BytesPerSector;
    666           } else {
    667             ASSERT (FALSE);
    668           }
    669 
    670           Media->ReadOnly = FALSE;
    671           gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
    672           gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
    673           return EFI_MEDIA_CHANGED;
    674         }
    675       } else if (BiosBlockIoDev->Bios.ErrorCode == BIOS_WRITE_PROTECTED) {
    676         Media->ReadOnly = TRUE;
    677         return EFI_WRITE_PROTECTED;
    678       }
    679 
    680       if (Media->RemovableMedia) {
    681         Media->MediaPresent = FALSE;
    682       }
    683 
    684       return EFI_DEVICE_ERROR;
    685     }
    686 
    687     Media->ReadOnly   = FALSE;
    688     TransferByteSize  = NumberOfBlocks * BlockSize;
    689     BufferSize        = BufferSize - TransferByteSize;
    690     TransferBuffer += TransferByteSize;
    691     Lba += NumberOfBlocks;
    692   }
    693 
    694   return EFI_SUCCESS;
    695 }
    696 
    697 /**
    698   Flush the Block Device.
    699 
    700   @param  This              Indicates a pointer to the calling context.
    701 
    702   @retval EFI_SUCCESS       All outstanding data was written to the device
    703   @retval EFI_DEVICE_ERROR  The device reported an error while writting back the data
    704   @retval EFI_NO_MEDIA      There is no media in the device.
    705 
    706 **/
    707 EFI_STATUS
    708 EFIAPI
    709 BiosBlockIoFlushBlocks (
    710   IN  EFI_BLOCK_IO_PROTOCOL  *This
    711   )
    712 {
    713   return EFI_SUCCESS;
    714 }
    715 
    716 /**
    717   Reset the Block Device.
    718 
    719   @param  This                 Indicates a pointer to the calling context.
    720   @param  ExtendedVerification Driver may perform diagnostics on reset.
    721 
    722   @retval EFI_SUCCESS          The device was reset.
    723   @retval EFI_DEVICE_ERROR     The device is not functioning properly and could
    724                                not be reset.
    725 
    726 **/
    727 EFI_STATUS
    728 EFIAPI
    729 BiosBlockIoReset (
    730   IN  EFI_BLOCK_IO_PROTOCOL *This,
    731   IN  BOOLEAN               ExtendedVerification
    732   )
    733 {
    734   BIOS_BLOCK_IO_DEV     *BiosBlockIoDev;
    735   EFI_IA32_REGISTER_SET Regs;
    736   UINTN                 CarryFlag;
    737 
    738   BiosBlockIoDev  = BIOS_BLOCK_IO_FROM_THIS (This);
    739 
    740   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
    741 
    742   Regs.H.AH       = 0x00;
    743   Regs.H.DL       = BiosBlockIoDev->Bios.Number;
    744   CarryFlag       = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
    745   DEBUG (
    746     (
    747     DEBUG_INIT, "BiosBlockIoReset: INT 13 00 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number, CarryFlag,
    748     Regs.H.AH
    749     )
    750     );
    751   if (CarryFlag != 0) {
    752     if (Regs.H.AL == BIOS_RESET_FAILED) {
    753       Regs.H.AH = 0x00;
    754       Regs.H.DL = BiosBlockIoDev->Bios.Number;
    755       CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
    756       DEBUG (
    757         (
    758         DEBUG_INIT, "BiosBlockIoReset: INT 13 00 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number, CarryFlag,
    759         Regs.H.AH
    760         )
    761         );
    762       if (CarryFlag != 0) {
    763         BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
    764         return EFI_DEVICE_ERROR;
    765       }
    766     }
    767   }
    768 
    769   return EFI_SUCCESS;
    770 }
    771 //
    772 //
    773 // These functions need to double buffer all data under 1MB!
    774 //
    775 //
    776 
    777 /**
    778   Read BufferSize bytes from Lba into Buffer.
    779 
    780   @param  This       Indicates a pointer to the calling context.
    781   @param  MediaId    Id of the media, changes every time the media is replaced.
    782   @param  Lba        The starting Logical Block Address to read from
    783   @param  BufferSize Size of Buffer, must be a multiple of device block size.
    784   @param  Buffer     A pointer to the destination buffer for the data. The caller is
    785                      responsible for either having implicit or explicit ownership of the buffer.
    786 
    787   @retval EFI_SUCCESS           The data was read correctly from the device.
    788   @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.
    789   @retval EFI_NO_MEDIA          There is no media in the device.
    790   @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.
    791   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
    792   @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
    793                                 or the buffer is not on proper alignment.
    794 
    795 **/
    796 EFI_STATUS
    797 EFIAPI
    798 Edd11BiosReadBlocks (
    799   IN  EFI_BLOCK_IO_PROTOCOL *This,
    800   IN  UINT32                MediaId,
    801   IN  EFI_LBA               Lba,
    802   IN  UINTN                 BufferSize,
    803   OUT VOID                  *Buffer
    804   )
    805 {
    806   EFI_BLOCK_IO_MEDIA        *Media;
    807   BIOS_BLOCK_IO_DEV         *BiosBlockIoDev;
    808   EDD_DEVICE_ADDRESS_PACKET *AddressPacket;
    809   //
    810   // I exist only for readability
    811   //
    812   EFI_IA32_REGISTER_SET     Regs;
    813   UINT64                    TransferBuffer;
    814   UINTN                     NumberOfBlocks;
    815   UINTN                     TransferByteSize;
    816   UINTN                     BlockSize;
    817   BIOS_LEGACY_DRIVE         *Bios;
    818   UINTN                     CarryFlag;
    819   UINTN                     MaxTransferBlocks;
    820   EFI_BLOCK_IO_PROTOCOL     *BlockIo;
    821 
    822   Media     = This->Media;
    823   BlockSize = Media->BlockSize;
    824 
    825   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
    826 
    827   if (MediaId != Media->MediaId) {
    828     return EFI_MEDIA_CHANGED;
    829   }
    830 
    831   if (Lba > Media->LastBlock) {
    832     return EFI_INVALID_PARAMETER;
    833   }
    834 
    835   if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
    836     return EFI_INVALID_PARAMETER;
    837   }
    838 
    839   if (BufferSize % BlockSize != 0) {
    840     return EFI_BAD_BUFFER_SIZE;
    841   }
    842 
    843   if (Buffer == NULL) {
    844     return EFI_INVALID_PARAMETER;
    845   }
    846 
    847   if (BufferSize == 0) {
    848     return EFI_SUCCESS;
    849   }
    850 
    851   BiosBlockIoDev    = BIOS_BLOCK_IO_FROM_THIS (This);
    852   AddressPacket     = mEddBufferUnder1Mb;
    853 
    854   MaxTransferBlocks = MAX_EDD11_XFER / BlockSize;
    855 
    856   TransferBuffer    = (UINT64)(UINTN) mEdd11Buffer;
    857   for (; BufferSize > 0;) {
    858     NumberOfBlocks  = BufferSize / BlockSize;
    859     NumberOfBlocks  = NumberOfBlocks > MaxTransferBlocks ? MaxTransferBlocks : NumberOfBlocks;
    860     //
    861     // Max transfer MaxTransferBlocks
    862     //
    863     AddressPacket->PacketSizeInBytes  = (UINT8) sizeof (EDD_DEVICE_ADDRESS_PACKET);
    864     AddressPacket->Zero               = 0;
    865     AddressPacket->NumberOfBlocks     = (UINT8) NumberOfBlocks;
    866     AddressPacket->Zero2              = 0;
    867     //
    868     // TransferBuffer has been 4KB alignment. Normalize TransferBuffer to make offset as 0 in seg:offset
    869     // format to transfer maximum 127 blocks of data.
    870     // Otherwise when offset adding data size exceeds 0xFFFF, if OpROM does not normalize TransferBuffer,
    871     // INT13 function 42H will return data boundary error 09H.
    872     //
    873     AddressPacket->SegOffset = (UINT32) LShiftU64 (RShiftU64(TransferBuffer, 4), 16);
    874     AddressPacket->Lba  = (UINT64) Lba;
    875 
    876     Regs.H.AH           = 0x42;
    877     Regs.H.DL           = BiosBlockIoDev->Bios.Number;
    878     Regs.X.SI           = EFI_OFFSET (AddressPacket);
    879     Regs.X.DS           = EFI_SEGMENT (AddressPacket);
    880 
    881     CarryFlag           = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
    882     DEBUG (
    883       (
    884       DEBUG_BLKIO, "Edd11BiosReadBlocks: INT 13 42 DL=%02x : CF=%d AH=%02x : LBA 0x%lx  Block(s) %0d \n",
    885       BiosBlockIoDev->Bios.Number, CarryFlag, Regs.H.AH, Lba, NumberOfBlocks
    886       )
    887       );
    888     Media->MediaPresent = TRUE;
    889     if (CarryFlag != 0) {
    890       //
    891       // Return Error Status
    892       //
    893       BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
    894       if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
    895         Media->MediaId++;
    896         Bios = &BiosBlockIoDev->Bios;
    897         if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
    898           if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
    899             Media->LastBlock  = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
    900             Media->BlockSize  = (UINT32) Bios->Parameters.BytesPerSector;
    901           } else {
    902             ASSERT (FALSE);
    903           }
    904 
    905           Media->ReadOnly = FALSE;
    906           gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
    907           gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
    908           return EFI_MEDIA_CHANGED;
    909         }
    910       }
    911 
    912       if (Media->RemovableMedia) {
    913         Media->MediaPresent = FALSE;
    914       }
    915 
    916       return EFI_DEVICE_ERROR;
    917     }
    918 
    919     TransferByteSize = NumberOfBlocks * BlockSize;
    920     CopyMem (Buffer, (VOID *) (UINTN) TransferBuffer, TransferByteSize);
    921     BufferSize  = BufferSize - TransferByteSize;
    922     Buffer      = (VOID *) ((UINT8 *) Buffer + TransferByteSize);
    923     Lba += NumberOfBlocks;
    924   }
    925 
    926   return EFI_SUCCESS;
    927 }
    928 
    929 /**
    930   Write BufferSize bytes from Lba into Buffer.
    931 
    932   @param  This       Indicates a pointer to the calling context.
    933   @param  MediaId    The media ID that the write request is for.
    934   @param  Lba        The starting logical block address to be written. The caller is
    935                      responsible for writing to only legitimate locations.
    936   @param  BufferSize Size of Buffer, must be a multiple of device block size.
    937   @param  Buffer     A pointer to the source buffer for the data.
    938 
    939   @retval EFI_SUCCESS           The data was written correctly to the device.
    940   @retval EFI_WRITE_PROTECTED   The device can not be written to.
    941   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
    942   @retval EFI_NO_MEDIA          There is no media in the device.
    943   @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
    944   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
    945   @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
    946                                 or the buffer is not on proper alignment.
    947 
    948 **/
    949 EFI_STATUS
    950 EFIAPI
    951 Edd11BiosWriteBlocks (
    952   IN  EFI_BLOCK_IO_PROTOCOL *This,
    953   IN  UINT32                MediaId,
    954   IN  EFI_LBA               Lba,
    955   IN  UINTN                 BufferSize,
    956   OUT VOID                  *Buffer
    957   )
    958 {
    959   EFI_BLOCK_IO_MEDIA        *Media;
    960   BIOS_BLOCK_IO_DEV         *BiosBlockIoDev;
    961   EDD_DEVICE_ADDRESS_PACKET *AddressPacket;
    962   //
    963   // I exist only for readability
    964   //
    965   EFI_IA32_REGISTER_SET     Regs;
    966   UINT64                    TransferBuffer;
    967   UINTN                     NumberOfBlocks;
    968   UINTN                     TransferByteSize;
    969   UINTN                     BlockSize;
    970   BIOS_LEGACY_DRIVE         *Bios;
    971   UINTN                     CarryFlag;
    972   UINTN                     MaxTransferBlocks;
    973   EFI_BLOCK_IO_PROTOCOL     *BlockIo;
    974 
    975   Media     = This->Media;
    976   BlockSize = Media->BlockSize;
    977 
    978   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
    979 
    980   if (MediaId != Media->MediaId) {
    981     return EFI_MEDIA_CHANGED;
    982   }
    983 
    984   if (Lba > Media->LastBlock) {
    985     return EFI_INVALID_PARAMETER;
    986   }
    987 
    988   if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
    989     return EFI_INVALID_PARAMETER;
    990   }
    991 
    992   if (BufferSize % BlockSize != 0) {
    993     return EFI_BAD_BUFFER_SIZE;
    994   }
    995 
    996   if (Buffer == NULL) {
    997     return EFI_INVALID_PARAMETER;
    998   }
    999 
   1000   if (BufferSize == 0) {
   1001     return EFI_SUCCESS;
   1002   }
   1003 
   1004   BiosBlockIoDev    = BIOS_BLOCK_IO_FROM_THIS (This);
   1005   AddressPacket     = mEddBufferUnder1Mb;
   1006 
   1007   MaxTransferBlocks = MAX_EDD11_XFER / BlockSize;
   1008 
   1009   TransferBuffer    = (UINT64)(UINTN) mEdd11Buffer;
   1010   for (; BufferSize > 0;) {
   1011     NumberOfBlocks  = BufferSize / BlockSize;
   1012     NumberOfBlocks  = NumberOfBlocks > MaxTransferBlocks ? MaxTransferBlocks : NumberOfBlocks;
   1013     //
   1014     // Max transfer MaxTransferBlocks
   1015     //
   1016     AddressPacket->PacketSizeInBytes  = (UINT8) sizeof (EDD_DEVICE_ADDRESS_PACKET);
   1017     AddressPacket->Zero               = 0;
   1018     AddressPacket->NumberOfBlocks     = (UINT8) NumberOfBlocks;
   1019     AddressPacket->Zero2              = 0;
   1020     //
   1021     // TransferBuffer has been 4KB alignment. Normalize TransferBuffer to make offset as 0 in seg:offset
   1022     // format to transfer maximum 127 blocks of data.
   1023     // Otherwise when offset adding data size exceeds 0xFFFF, if OpROM does not normalize TransferBuffer,
   1024     // INT13 function 42H will return data boundary error 09H.
   1025     //
   1026     AddressPacket->SegOffset = (UINT32) LShiftU64 (RShiftU64(TransferBuffer, 4), 16);
   1027     AddressPacket->Lba  = (UINT64) Lba;
   1028 
   1029     Regs.H.AH           = 0x43;
   1030     Regs.H.AL           = 0x00;
   1031     //
   1032     // Write Verify disable
   1033     //
   1034     Regs.H.DL         = BiosBlockIoDev->Bios.Number;
   1035     Regs.X.SI         = EFI_OFFSET (AddressPacket);
   1036     Regs.X.DS         = EFI_SEGMENT (AddressPacket);
   1037 
   1038     TransferByteSize  = NumberOfBlocks * BlockSize;
   1039     CopyMem ((VOID *) (UINTN) TransferBuffer, Buffer, TransferByteSize);
   1040 
   1041     CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
   1042     DEBUG (
   1043       (
   1044       DEBUG_BLKIO, "Edd11BiosWriteBlocks: INT 13 43 DL=%02x : CF=%d AH=%02x\n: LBA 0x%lx  Block(s) %0d \n",
   1045       BiosBlockIoDev->Bios.Number, CarryFlag, Regs.H.AH, Lba, NumberOfBlocks
   1046       )
   1047       );
   1048     Media->MediaPresent = TRUE;
   1049     if (CarryFlag != 0) {
   1050       //
   1051       // Return Error Status
   1052       //
   1053       BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
   1054       if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
   1055         Media->MediaId++;
   1056         Bios = &BiosBlockIoDev->Bios;
   1057         if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
   1058           if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
   1059             Media->LastBlock  = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
   1060             Media->BlockSize  = (UINT32) Bios->Parameters.BytesPerSector;
   1061           } else {
   1062             ASSERT (FALSE);
   1063           }
   1064 
   1065           Media->ReadOnly = FALSE;
   1066           gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
   1067           gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
   1068           return EFI_MEDIA_CHANGED;
   1069         }
   1070       } else if (BiosBlockIoDev->Bios.ErrorCode == BIOS_WRITE_PROTECTED) {
   1071         Media->ReadOnly = TRUE;
   1072         return EFI_WRITE_PROTECTED;
   1073       }
   1074 
   1075       if (Media->RemovableMedia) {
   1076         Media->MediaPresent = FALSE;
   1077       }
   1078 
   1079       return EFI_DEVICE_ERROR;
   1080     }
   1081 
   1082     Media->ReadOnly = FALSE;
   1083     BufferSize      = BufferSize - TransferByteSize;
   1084     Buffer          = (VOID *) ((UINT8 *) Buffer + TransferByteSize);
   1085     Lba += NumberOfBlocks;
   1086   }
   1087 
   1088   return EFI_SUCCESS;
   1089 }
   1090 
   1091 /**
   1092   Read BufferSize bytes from Lba into Buffer.
   1093 
   1094   @param  This       Indicates a pointer to the calling context.
   1095   @param  MediaId    Id of the media, changes every time the media is replaced.
   1096   @param  Lba        The starting Logical Block Address to read from
   1097   @param  BufferSize Size of Buffer, must be a multiple of device block size.
   1098   @param  Buffer     A pointer to the destination buffer for the data. The caller is
   1099                      responsible for either having implicit or explicit ownership of the buffer.
   1100 
   1101   @retval EFI_SUCCESS           The data was read correctly from the device.
   1102   @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.
   1103   @retval EFI_NO_MEDIA          There is no media in the device.
   1104   @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.
   1105   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
   1106   @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
   1107                                 or the buffer is not on proper alignment.
   1108 
   1109 **/
   1110 EFI_STATUS
   1111 EFIAPI
   1112 BiosReadLegacyDrive (
   1113   IN  EFI_BLOCK_IO_PROTOCOL *This,
   1114   IN  UINT32                MediaId,
   1115   IN  EFI_LBA               Lba,
   1116   IN  UINTN                 BufferSize,
   1117   OUT VOID                  *Buffer
   1118   )
   1119 {
   1120   EFI_BLOCK_IO_MEDIA    *Media;
   1121   BIOS_BLOCK_IO_DEV     *BiosBlockIoDev;
   1122   EFI_IA32_REGISTER_SET Regs;
   1123   UINTN                 UpperCylinder;
   1124   UINTN                 Temp;
   1125   UINTN                 Cylinder;
   1126   UINTN                 Head;
   1127   UINTN                 Sector;
   1128   UINTN                 NumberOfBlocks;
   1129   UINTN                 TransferByteSize;
   1130   UINTN                 ShortLba;
   1131   UINTN                 CheckLba;
   1132   UINTN                 BlockSize;
   1133   BIOS_LEGACY_DRIVE     *Bios;
   1134   UINTN                 CarryFlag;
   1135   UINTN                 Retry;
   1136   EFI_BLOCK_IO_PROTOCOL *BlockIo;
   1137 
   1138   Media     = This->Media;
   1139   BlockSize = Media->BlockSize;
   1140 
   1141   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
   1142 
   1143   if (MediaId != Media->MediaId) {
   1144     return EFI_MEDIA_CHANGED;
   1145   }
   1146 
   1147   if (Lba > Media->LastBlock) {
   1148     return EFI_INVALID_PARAMETER;
   1149   }
   1150 
   1151   if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
   1152     return EFI_INVALID_PARAMETER;
   1153   }
   1154 
   1155   if (BufferSize % BlockSize != 0) {
   1156     return EFI_BAD_BUFFER_SIZE;
   1157   }
   1158 
   1159   if (Buffer == NULL) {
   1160     return EFI_INVALID_PARAMETER;
   1161   }
   1162 
   1163   if (BufferSize == 0) {
   1164     return EFI_SUCCESS;
   1165   }
   1166 
   1167   BiosBlockIoDev  = BIOS_BLOCK_IO_FROM_THIS (This);
   1168   ShortLba        = (UINTN) Lba;
   1169 
   1170   while (BufferSize != 0) {
   1171     //
   1172     // Compute I/O location in Sector, Head, Cylinder format
   1173     //
   1174     Sector    = (ShortLba % BiosBlockIoDev->Bios.MaxSector) + 1;
   1175     Temp      = ShortLba / BiosBlockIoDev->Bios.MaxSector;
   1176     Head      = Temp % (BiosBlockIoDev->Bios.MaxHead + 1);
   1177     Cylinder  = Temp / (BiosBlockIoDev->Bios.MaxHead + 1);
   1178 
   1179     //
   1180     // Limit transfer to this Head & Cylinder
   1181     //
   1182     NumberOfBlocks  = BufferSize / BlockSize;
   1183     Temp            = BiosBlockIoDev->Bios.MaxSector - Sector + 1;
   1184     NumberOfBlocks  = NumberOfBlocks > Temp ? Temp : NumberOfBlocks;
   1185 
   1186     Retry           = 3;
   1187     do {
   1188       //
   1189       // Perform the IO
   1190       //
   1191       Regs.H.AH     = 2;
   1192       Regs.H.AL     = (UINT8) NumberOfBlocks;
   1193       Regs.H.DL     = BiosBlockIoDev->Bios.Number;
   1194 
   1195       UpperCylinder = (Cylinder & 0x0f00) >> 2;
   1196 
   1197       CheckLba      = Cylinder * (BiosBlockIoDev->Bios.MaxHead + 1) + Head;
   1198       CheckLba      = CheckLba * BiosBlockIoDev->Bios.MaxSector + Sector - 1;
   1199 
   1200       DEBUG (
   1201         (DEBUG_BLKIO,
   1202         "RLD: LBA %x (%x), Sector %x (%x), Head %x (%x), Cyl %x, UCyl %x\n",
   1203         ShortLba,
   1204         CheckLba,
   1205         Sector,
   1206         BiosBlockIoDev->Bios.MaxSector,
   1207         Head,
   1208         BiosBlockIoDev->Bios.MaxHead,
   1209         Cylinder,
   1210         UpperCylinder)
   1211         );
   1212       ASSERT (CheckLba == ShortLba);
   1213 
   1214       Regs.H.CL = (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff));
   1215       Regs.H.DH = (UINT8) (Head & 0x3f);
   1216       Regs.H.CH = (UINT8) (Cylinder & 0xff);
   1217 
   1218       Regs.X.BX = EFI_OFFSET (mEdd11Buffer);
   1219       Regs.X.ES = EFI_SEGMENT (mEdd11Buffer);
   1220 
   1221       DEBUG (
   1222         (DEBUG_BLKIO,
   1223         "INT 13h: AX:(02%02x) DX:(%02x%02x) CX:(%02x%02x) BX:(%04x) ES:(%04x)\n",
   1224         Regs.H.AL,
   1225         (UINT8) (Head & 0x3f),
   1226         Regs.H.DL,
   1227         (UINT8) (Cylinder & 0xff),
   1228         (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff)),
   1229         EFI_OFFSET (mEdd11Buffer),
   1230         EFI_SEGMENT (mEdd11Buffer))
   1231         );
   1232 
   1233       CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
   1234       DEBUG (
   1235         (
   1236         DEBUG_BLKIO, "BiosReadLegacyDrive: INT 13 02 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number,
   1237         CarryFlag, Regs.H.AH
   1238         )
   1239         );
   1240       Retry--;
   1241     } while (CarryFlag != 0 && Retry != 0 && Regs.H.AH != BIOS_DISK_CHANGED);
   1242 
   1243     Media->MediaPresent = TRUE;
   1244     if (CarryFlag != 0) {
   1245       //
   1246       // Return Error Status
   1247       //
   1248       BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
   1249       if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
   1250         Media->MediaId++;
   1251         Bios = &BiosBlockIoDev->Bios;
   1252         if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
   1253           //
   1254           // If the size of the media changed we need to reset the disk geometry
   1255           //
   1256           if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
   1257             Media->LastBlock  = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
   1258             Media->BlockSize  = (UINT32) Bios->Parameters.BytesPerSector;
   1259           } else {
   1260             //
   1261             // Legacy Interfaces
   1262             //
   1263             Media->LastBlock  = (Bios->MaxHead + 1) * Bios->MaxSector * (Bios->MaxCylinder + 1) - 1;
   1264             Media->BlockSize  = 512;
   1265           }
   1266 
   1267           Media->ReadOnly = FALSE;
   1268           gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
   1269           gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
   1270           return EFI_MEDIA_CHANGED;
   1271         }
   1272       }
   1273 
   1274       if (Media->RemovableMedia) {
   1275         Media->MediaPresent = FALSE;
   1276       }
   1277 
   1278       return EFI_DEVICE_ERROR;
   1279     }
   1280 
   1281     TransferByteSize = NumberOfBlocks * BlockSize;
   1282     CopyMem (Buffer, mEdd11Buffer, TransferByteSize);
   1283 
   1284     ShortLba    = ShortLba + NumberOfBlocks;
   1285     BufferSize  = BufferSize - TransferByteSize;
   1286     Buffer      = (VOID *) ((UINT8 *) Buffer + TransferByteSize);
   1287   }
   1288 
   1289   return EFI_SUCCESS;
   1290 }
   1291 
   1292 /**
   1293   Write BufferSize bytes from Lba into Buffer.
   1294 
   1295   @param  This       Indicates a pointer to the calling context.
   1296   @param  MediaId    The media ID that the write request is for.
   1297   @param  Lba        The starting logical block address to be written. The caller is
   1298                      responsible for writing to only legitimate locations.
   1299   @param  BufferSize Size of Buffer, must be a multiple of device block size.
   1300   @param  Buffer     A pointer to the source buffer for the data.
   1301 
   1302   @retval EFI_SUCCESS           The data was written correctly to the device.
   1303   @retval EFI_WRITE_PROTECTED   The device can not be written to.
   1304   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
   1305   @retval EFI_NO_MEDIA          There is no media in the device.
   1306   @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
   1307   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
   1308   @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
   1309                                 or the buffer is not on proper alignment.
   1310 
   1311 **/
   1312 EFI_STATUS
   1313 EFIAPI
   1314 BiosWriteLegacyDrive (
   1315   IN  EFI_BLOCK_IO_PROTOCOL *This,
   1316   IN  UINT32                MediaId,
   1317   IN  EFI_LBA               Lba,
   1318   IN  UINTN                 BufferSize,
   1319   OUT VOID                  *Buffer
   1320   )
   1321 {
   1322   EFI_BLOCK_IO_MEDIA    *Media;
   1323   BIOS_BLOCK_IO_DEV     *BiosBlockIoDev;
   1324   EFI_IA32_REGISTER_SET Regs;
   1325   UINTN                 UpperCylinder;
   1326   UINTN                 Temp;
   1327   UINTN                 Cylinder;
   1328   UINTN                 Head;
   1329   UINTN                 Sector;
   1330   UINTN                 NumberOfBlocks;
   1331   UINTN                 TransferByteSize;
   1332   UINTN                 ShortLba;
   1333   UINTN                 CheckLba;
   1334   UINTN                 BlockSize;
   1335   BIOS_LEGACY_DRIVE     *Bios;
   1336   UINTN                 CarryFlag;
   1337   UINTN                 Retry;
   1338   EFI_BLOCK_IO_PROTOCOL *BlockIo;
   1339 
   1340   Media     = This->Media;
   1341   BlockSize = Media->BlockSize;
   1342 
   1343   ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
   1344 
   1345   if (MediaId != Media->MediaId) {
   1346     return EFI_MEDIA_CHANGED;
   1347   }
   1348 
   1349   if (Lba > Media->LastBlock) {
   1350     return EFI_INVALID_PARAMETER;
   1351   }
   1352 
   1353   if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
   1354     return EFI_INVALID_PARAMETER;
   1355   }
   1356 
   1357   if (BufferSize % BlockSize != 0) {
   1358     return EFI_BAD_BUFFER_SIZE;
   1359   }
   1360 
   1361   if (Buffer == NULL) {
   1362     return EFI_INVALID_PARAMETER;
   1363   }
   1364 
   1365   if (BufferSize == 0) {
   1366     return EFI_SUCCESS;
   1367   }
   1368 
   1369   BiosBlockIoDev  = BIOS_BLOCK_IO_FROM_THIS (This);
   1370   ShortLba        = (UINTN) Lba;
   1371 
   1372   while (BufferSize != 0) {
   1373     //
   1374     // Compute I/O location in Sector, Head, Cylinder format
   1375     //
   1376     Sector    = (ShortLba % BiosBlockIoDev->Bios.MaxSector) + 1;
   1377     Temp      = ShortLba / BiosBlockIoDev->Bios.MaxSector;
   1378     Head      = Temp % (BiosBlockIoDev->Bios.MaxHead + 1);
   1379     Cylinder  = Temp / (BiosBlockIoDev->Bios.MaxHead + 1);
   1380 
   1381     //
   1382     // Limit transfer to this Head & Cylinder
   1383     //
   1384     NumberOfBlocks  = BufferSize / BlockSize;
   1385     Temp            = BiosBlockIoDev->Bios.MaxSector - Sector + 1;
   1386     NumberOfBlocks  = NumberOfBlocks > Temp ? Temp : NumberOfBlocks;
   1387 
   1388     Retry           = 3;
   1389     do {
   1390       //
   1391       // Perform the IO
   1392       //
   1393       Regs.H.AH     = 3;
   1394       Regs.H.AL     = (UINT8) NumberOfBlocks;
   1395       Regs.H.DL     = BiosBlockIoDev->Bios.Number;
   1396 
   1397       UpperCylinder = (Cylinder & 0x0f00) >> 2;
   1398 
   1399       CheckLba      = Cylinder * (BiosBlockIoDev->Bios.MaxHead + 1) + Head;
   1400       CheckLba      = CheckLba * BiosBlockIoDev->Bios.MaxSector + Sector - 1;
   1401 
   1402       DEBUG (
   1403         (DEBUG_BLKIO,
   1404         "RLD: LBA %x (%x), Sector %x (%x), Head %x (%x), Cyl %x, UCyl %x\n",
   1405         ShortLba,
   1406         CheckLba,
   1407         Sector,
   1408         BiosBlockIoDev->Bios.MaxSector,
   1409         Head,
   1410         BiosBlockIoDev->Bios.MaxHead,
   1411         Cylinder,
   1412         UpperCylinder)
   1413         );
   1414       ASSERT (CheckLba == ShortLba);
   1415 
   1416       Regs.H.CL         = (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff));
   1417       Regs.H.DH         = (UINT8) (Head & 0x3f);
   1418       Regs.H.CH         = (UINT8) (Cylinder & 0xff);
   1419 
   1420       Regs.X.BX         = EFI_OFFSET (mEdd11Buffer);
   1421       Regs.X.ES         = EFI_SEGMENT (mEdd11Buffer);
   1422 
   1423       TransferByteSize  = NumberOfBlocks * BlockSize;
   1424       CopyMem (mEdd11Buffer, Buffer, TransferByteSize);
   1425 
   1426       DEBUG (
   1427         (DEBUG_BLKIO,
   1428         "INT 13h: AX:(03%02x) DX:(%02x%02x) CX:(%02x%02x) BX:(%04x) ES:(%04x)\n",
   1429         Regs.H.AL,
   1430         (UINT8) (Head & 0x3f),
   1431         Regs.H.DL,
   1432         (UINT8) (Cylinder & 0xff),
   1433         (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff)),
   1434         EFI_OFFSET (mEdd11Buffer),
   1435         EFI_SEGMENT (mEdd11Buffer))
   1436         );
   1437 
   1438       CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
   1439       DEBUG (
   1440         (
   1441         DEBUG_BLKIO, "BiosWriteLegacyDrive: INT 13 03 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number,
   1442         CarryFlag, Regs.H.AH
   1443         )
   1444         );
   1445       Retry--;
   1446     } while (CarryFlag != 0 && Retry != 0 && Regs.H.AH != BIOS_DISK_CHANGED);
   1447 
   1448     Media->MediaPresent = TRUE;
   1449     if (CarryFlag != 0) {
   1450       //
   1451       // Return Error Status
   1452       //
   1453       BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
   1454       if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
   1455         Media->MediaId++;
   1456         Bios = &BiosBlockIoDev->Bios;
   1457         if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
   1458           if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
   1459             Media->LastBlock  = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
   1460             Media->BlockSize  = (UINT32) Bios->Parameters.BytesPerSector;
   1461           } else {
   1462             //
   1463             // Legacy Interfaces
   1464             //
   1465             Media->LastBlock  = (Bios->MaxHead + 1) * Bios->MaxSector * (Bios->MaxCylinder + 1) - 1;
   1466             Media->BlockSize  = 512;
   1467           }
   1468           //
   1469           // If the size of the media changed we need to reset the disk geometry
   1470           //
   1471           Media->ReadOnly = FALSE;
   1472           gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
   1473           gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
   1474           return EFI_MEDIA_CHANGED;
   1475         }
   1476       } else if (BiosBlockIoDev->Bios.ErrorCode == BIOS_WRITE_PROTECTED) {
   1477         Media->ReadOnly = TRUE;
   1478         return EFI_WRITE_PROTECTED;
   1479       }
   1480 
   1481       if (Media->RemovableMedia) {
   1482         Media->MediaPresent = FALSE;
   1483       }
   1484 
   1485       return EFI_DEVICE_ERROR;
   1486     }
   1487 
   1488     Media->ReadOnly = FALSE;
   1489     ShortLba        = ShortLba + NumberOfBlocks;
   1490     BufferSize      = BufferSize - TransferByteSize;
   1491     Buffer          = (VOID *) ((UINT8 *) Buffer + TransferByteSize);
   1492   }
   1493 
   1494   return EFI_SUCCESS;
   1495 }
   1496