/** @file Routines that use BIOS to support INT 13 devices. Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #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) LShiftU64 (RShiftU64(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) LShiftU64 (RShiftU64(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; }