2 Routines that use BIOS to support INT 13 devices.
4 Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "BiosBlkIo.h"
13 // Module global variables
16 // Address packet is a buffer under 1 MB for all version EDD calls
18 extern EDD_DEVICE_ADDRESS_PACKET
*mEddBufferUnder1Mb
;
21 // This is a buffer for INT 13h func 48 information
23 extern BIOS_LEGACY_DRIVE
*mLegacyDriverUnder1Mb
;
26 // Buffer of 0xFE00 bytes for EDD 1.1 transfer must be under 1 MB
27 // 0xFE00 bytes is the max transfer size supported.
29 extern VOID
*mEdd11Buffer
;
33 Initialize block I/O device instance
35 @param Dev Instance of block I/O device instance
37 @retval TRUE Initialization succeeds.
38 @retval FALSE Initialization fails.
43 IN BIOS_BLOCK_IO_DEV
*Dev
46 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
47 EFI_BLOCK_IO_MEDIA
*BlockMedia
;
48 BIOS_LEGACY_DRIVE
*Bios
;
50 BlockIo
= &Dev
->BlockIo
;
51 BlockIo
->Media
= &Dev
->BlockMedia
;
52 BlockMedia
= BlockIo
->Media
;
55 if (Int13GetDeviceParameters (Dev
, Bios
) != 0) {
56 if (Int13Extensions (Dev
, Bios
) != 0) {
57 BlockMedia
->LastBlock
= (EFI_LBA
) Bios
->Parameters
.PhysicalSectors
- 1;
58 BlockMedia
->BlockSize
= (UINT32
) Bios
->Parameters
.BytesPerSector
;
60 if ((Bios
->Parameters
.Flags
& EDD_DEVICE_REMOVABLE
) == EDD_DEVICE_REMOVABLE
) {
61 BlockMedia
->RemovableMedia
= TRUE
;
68 BlockMedia
->BlockSize
= 512;
69 BlockMedia
->LastBlock
= (Bios
->MaxHead
+ 1) * Bios
->MaxSector
* (Bios
->MaxCylinder
+ 1) - 1;
72 DEBUG ((DEBUG_INIT
, "BlockSize = %d LastBlock = %d\n", BlockMedia
->BlockSize
, BlockMedia
->LastBlock
));
74 BlockMedia
->LogicalPartition
= FALSE
;
75 BlockMedia
->WriteCaching
= FALSE
;
78 // BugBug: Need to set this for removable media devices if they do not
81 BlockMedia
->ReadOnly
= FALSE
;
82 BlockMedia
->MediaPresent
= TRUE
;
84 BlockIo
->Reset
= BiosBlockIoReset
;
85 BlockIo
->FlushBlocks
= BiosBlockIoFlushBlocks
;
87 if (!Bios
->ExtendedInt13
) {
91 BlockIo
->ReadBlocks
= BiosReadLegacyDrive
;
92 BlockIo
->WriteBlocks
= BiosWriteLegacyDrive
;
93 } else if ((Bios
->EddVersion
== EDD_VERSION_30
) && (Bios
->Extensions64Bit
)) {
95 // EDD 3.0 Required for Device path, but extended reads are not required.
97 BlockIo
->ReadBlocks
= Edd30BiosReadBlocks
;
98 BlockIo
->WriteBlocks
= Edd30BiosWriteBlocks
;
101 // Assume EDD 1.1 - Read and Write functions.
102 // This could be EDD 3.0 without Extensions64Bit being set.
103 // If it's EDD 1.1 this will work, but the device path will not
104 // be correct. This will cause confusion to EFI OS installation.
106 BlockIo
->ReadBlocks
= Edd11BiosReadBlocks
;
107 BlockIo
->WriteBlocks
= Edd11BiosWriteBlocks
;
110 BlockMedia
->LogicalPartition
= FALSE
;
111 BlockMedia
->WriteCaching
= FALSE
;
120 Gets parameters of block I/O device.
122 @param BiosBlockIoDev Instance of block I/O device.
123 @param Drive Legacy drive.
125 @return Result of device parameter retrieval.
129 Int13GetDeviceParameters (
130 IN BIOS_BLOCK_IO_DEV
*BiosBlockIoDev
,
131 IN BIOS_LEGACY_DRIVE
*Drive
136 EFI_IA32_REGISTER_SET Regs
;
138 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
141 Regs
.H
.DL
= Drive
->Number
;
142 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
143 DEBUG ((DEBUG_INIT
, "Int13GetDeviceParameters: INT 13 08 DL=%02x : CF=%d AH=%02x\n", Drive
->Number
, CarryFlag
, Regs
.H
.AH
));
144 if (CarryFlag
!= 0 || Regs
.H
.AH
!= 0x00) {
145 Drive
->ErrorCode
= Regs
.H
.AH
;
150 if (Regs
.H
.BL
== 0x10) {
151 Drive
->AtapiFloppy
= TRUE
;
153 Drive
->MaxHead
= Regs
.H
.DH
;
154 Drive
->MaxSector
= Regs
.H
.CL
;
155 Drive
->MaxCylinder
= Regs
.H
.CH
;
156 if (Drive
->MaxSector
== 0) {
158 // BugBug: You can not trust the Carry flag.
164 Drive
->MaxHead
= (UINT8
) (Regs
.H
.DH
& 0x3f);
165 Cylinder
= (UINT16
) (((UINT16
) Regs
.H
.DH
& 0xc0) << 4);
166 Cylinder
= (UINT16
) (Cylinder
| ((UINT16
) Regs
.H
.CL
& 0xc0) << 2);
167 Drive
->MaxCylinder
= (UINT16
) (Cylinder
+ Regs
.H
.CH
);
168 Drive
->MaxSector
= (UINT8
) (Regs
.H
.CL
& 0x3f);
175 Extension of INT13 call.
177 @param BiosBlockIoDev Instance of block I/O device.
178 @param Drive Legacy drive.
180 @return Result of this extension.
185 IN BIOS_BLOCK_IO_DEV
*BiosBlockIoDev
,
186 IN BIOS_LEGACY_DRIVE
*Drive
190 EFI_IA32_REGISTER_SET Regs
;
192 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
196 Regs
.H
.DL
= Drive
->Number
;
197 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
198 DEBUG ((DEBUG_INIT
, "Int13Extensions: INT 13 41 DL=%02x : CF=%d BX=%04x\n", Drive
->Number
, CarryFlag
, Regs
.X
.BX
));
199 if (CarryFlag
!= 0 || Regs
.X
.BX
!= 0xaa55) {
200 Drive
->ExtendedInt13
= FALSE
;
201 Drive
->DriveLockingAndEjecting
= FALSE
;
206 Drive
->EddVersion
= Regs
.H
.AH
;
207 Drive
->ExtendedInt13
= (BOOLEAN
) ((Regs
.X
.CX
& 0x01) == 0x01);
208 Drive
->DriveLockingAndEjecting
= (BOOLEAN
) ((Regs
.X
.CX
& 0x02) == 0x02);
209 Drive
->Edd
= (BOOLEAN
) ((Regs
.X
.CX
& 0x04) == 0x04);
210 Drive
->Extensions64Bit
= (BOOLEAN
) (Regs
.X
.CX
& 0x08);
212 Drive
->ParametersValid
= (UINT8
) GetDriveParameters (BiosBlockIoDev
, Drive
);
217 Gets parameters of legacy drive.
219 @param BiosBlockIoDev Instance of block I/O device.
220 @param Drive Legacy drive.
222 @return Result of drive parameter retrieval.
227 IN BIOS_BLOCK_IO_DEV
*BiosBlockIoDev
,
228 IN BIOS_LEGACY_DRIVE
*Drive
232 EFI_IA32_REGISTER_SET Regs
;
235 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
238 Regs
.H
.DL
= Drive
->Number
;
241 // EDD Buffer must be passed in with max buffer size as first entry in the buffer
243 mLegacyDriverUnder1Mb
->Parameters
.StructureSize
= (UINT16
) sizeof (EDD_DRIVE_PARAMETERS
);
244 Regs
.X
.DS
= EFI_SEGMENT ((UINTN
)(&mLegacyDriverUnder1Mb
->Parameters
));
245 Regs
.X
.SI
= EFI_OFFSET ((UINTN
)(&mLegacyDriverUnder1Mb
->Parameters
));
246 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
247 DEBUG ((DEBUG_INIT
, "GetDriveParameters: INT 13 48 DL=%02x : CF=%d AH=%02x\n", Drive
->Number
, CarryFlag
, Regs
.H
.AH
));
248 if (CarryFlag
!= 0 || Regs
.H
.AH
!= 0x00) {
249 Drive
->ErrorCode
= Regs
.H
.AH
;
250 SetMem (&Drive
->Parameters
, sizeof (Drive
->Parameters
), 0xaf);
254 // We only have one buffer < 1MB, so copy into our instance data
258 &mLegacyDriverUnder1Mb
->Parameters
,
259 sizeof (Drive
->Parameters
)
262 if (Drive
->AtapiFloppy
) {
267 Regs
.H
.DL
= Drive
->Number
;
268 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
269 DEBUG ((DEBUG_INIT
, "GetDriveParameters: INT 13 20 DL=%02x : CF=%d AL=%02x\n", Drive
->Number
, CarryFlag
, Regs
.H
.AL
));
270 if (CarryFlag
!= 0) {
272 // Media not present or unknown media present
274 if ((Drive
->Parameters
.Flags
& EDD_GEOMETRY_VALID
) == EDD_GEOMETRY_VALID
) {
275 Drive
->MaxHead
= (UINT8
) (Drive
->Parameters
.MaxHeads
- 1);
276 Drive
->MaxSector
= (UINT8
) Drive
->Parameters
.SectorsPerTrack
;
277 ASSERT (Drive
->MaxSector
!= 0);
278 Drive
->MaxCylinder
= (UINT16
) (Drive
->Parameters
.MaxCylinders
- 1);
281 Drive
->MaxSector
= 1;
282 Drive
->MaxCylinder
= 0;
295 Drive
->MaxSector
= 9;
296 Drive
->MaxCylinder
= 79;
304 Drive
->MaxSector
= 18;
305 Drive
->MaxCylinder
= 79;
313 Drive
->MaxSector
= 36;
314 Drive
->MaxCylinder
= 79;
322 Drive
->MaxSector
= 9;
323 Drive
->MaxCylinder
= 39;
331 Drive
->MaxSector
= 15;
332 Drive
->MaxCylinder
= 79;
347 if ((Drive
->Parameters
.Flags
& EDD_GEOMETRY_VALID
) == EDD_GEOMETRY_VALID
) {
348 Drive
->MaxHead
= (UINT8
) (Drive
->Parameters
.MaxHeads
- 1);
349 Drive
->MaxSector
= (UINT8
) Drive
->Parameters
.SectorsPerTrack
;
350 ASSERT (Drive
->MaxSector
!= 0);
351 Drive
->MaxCylinder
= (UINT16
) (Drive
->Parameters
.MaxCylinders
- 1);
354 Drive
->MaxSector
= 1;
355 Drive
->MaxCylinder
= 0;
361 // Unknown media type.
364 Drive
->MaxSector
= 1;
365 Drive
->MaxCylinder
= 0;
370 Drive
->Parameters
.PhysicalSectors
= (Drive
->MaxHead
+ 1) * Drive
->MaxSector
* (Drive
->MaxCylinder
+ 1);
371 Drive
->Parameters
.BytesPerSector
= 512;
374 // This data comes from the BIOS so it may not allways be valid
375 // since the BIOS may reuse this buffer for future accesses
377 PointerMath
= EFI_SEGMENT (Drive
->Parameters
.Fdpt
) << 4;
378 PointerMath
+= EFI_OFFSET (Drive
->Parameters
.Fdpt
);
379 Drive
->FdptPointer
= (VOID
*) PointerMath
;
388 Read BufferSize bytes from Lba into Buffer.
390 @param This Indicates a pointer to the calling context.
391 @param MediaId Id of the media, changes every time the media is replaced.
392 @param Lba The starting Logical Block Address to read from
393 @param BufferSize Size of Buffer, must be a multiple of device block size.
394 @param Buffer A pointer to the destination buffer for the data. The caller is
395 responsible for either having implicit or explicit ownership of the buffer.
397 @retval EFI_SUCCESS The data was read correctly from the device.
398 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
399 @retval EFI_NO_MEDIA There is no media in the device.
400 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
401 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
402 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
403 or the buffer is not on proper alignment.
408 Edd30BiosReadBlocks (
409 IN EFI_BLOCK_IO_PROTOCOL
*This
,
416 EFI_BLOCK_IO_MEDIA
*Media
;
417 BIOS_BLOCK_IO_DEV
*BiosBlockIoDev
;
418 EDD_DEVICE_ADDRESS_PACKET
*AddressPacket
;
420 // I exist only for readability
422 EFI_IA32_REGISTER_SET Regs
;
423 UINT64 TransferBuffer
;
424 UINTN NumberOfBlocks
;
425 UINTN TransferByteSize
;
427 BIOS_LEGACY_DRIVE
*Bios
;
429 UINTN MaxTransferBlocks
;
430 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
433 BlockSize
= Media
->BlockSize
;
435 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
437 if (MediaId
!= Media
->MediaId
) {
438 return EFI_MEDIA_CHANGED
;
441 if (Lba
> Media
->LastBlock
) {
442 return EFI_INVALID_PARAMETER
;
445 if ((Lba
+ (BufferSize
/ BlockSize
) - 1) > Media
->LastBlock
) {
446 return EFI_INVALID_PARAMETER
;
449 if (BufferSize
% BlockSize
!= 0) {
450 return EFI_BAD_BUFFER_SIZE
;
453 if (Buffer
== NULL
) {
454 return EFI_INVALID_PARAMETER
;
457 if (BufferSize
== 0) {
461 BiosBlockIoDev
= BIOS_BLOCK_IO_FROM_THIS (This
);
462 AddressPacket
= mEddBufferUnder1Mb
;
464 MaxTransferBlocks
= MAX_EDD11_XFER
/ BlockSize
;
466 TransferBuffer
= (UINT64
)(UINTN
) Buffer
;
467 for (; BufferSize
> 0;) {
468 NumberOfBlocks
= BufferSize
/ BlockSize
;
469 NumberOfBlocks
= NumberOfBlocks
> MaxTransferBlocks
? MaxTransferBlocks
: NumberOfBlocks
;
471 // Max transfer MaxTransferBlocks
473 AddressPacket
->PacketSizeInBytes
= (UINT8
) sizeof (EDD_DEVICE_ADDRESS_PACKET
);
474 AddressPacket
->Zero
= 0;
475 AddressPacket
->NumberOfBlocks
= (UINT8
) NumberOfBlocks
;
476 AddressPacket
->Zero2
= 0;
477 AddressPacket
->SegOffset
= 0xffffffff;
478 AddressPacket
->Lba
= (UINT64
) Lba
;
479 AddressPacket
->TransferBuffer
= TransferBuffer
;
482 Regs
.H
.DL
= BiosBlockIoDev
->Bios
.Number
;
483 Regs
.X
.SI
= EFI_OFFSET (AddressPacket
);
484 Regs
.X
.DS
= EFI_SEGMENT (AddressPacket
);
486 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
489 DEBUG_BLKIO
, "Edd30BiosReadBlocks: INT 13 42 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev
->Bios
.Number
,
494 Media
->MediaPresent
= TRUE
;
495 if (CarryFlag
!= 0) {
497 // Return Error Status
499 BiosBlockIoDev
->Bios
.ErrorCode
= Regs
.H
.AH
;
500 if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_DISK_CHANGED
) {
502 Bios
= &BiosBlockIoDev
->Bios
;
503 if (Int13GetDeviceParameters (BiosBlockIoDev
, Bios
) != 0) {
504 if (Int13Extensions (BiosBlockIoDev
, Bios
) != 0) {
505 Media
->LastBlock
= (EFI_LBA
) Bios
->Parameters
.PhysicalSectors
- 1;
506 Media
->BlockSize
= (UINT32
) Bios
->Parameters
.BytesPerSector
;
511 Media
->ReadOnly
= FALSE
;
512 gBS
->HandleProtocol (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
513 gBS
->ReinstallProtocolInterface (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, BlockIo
, BlockIo
);
514 return EFI_MEDIA_CHANGED
;
518 if (Media
->RemovableMedia
) {
519 Media
->MediaPresent
= FALSE
;
522 return EFI_DEVICE_ERROR
;
525 TransferByteSize
= NumberOfBlocks
* BlockSize
;
526 BufferSize
= BufferSize
- TransferByteSize
;
527 TransferBuffer
+= TransferByteSize
;
528 Lba
+= NumberOfBlocks
;
535 Write BufferSize bytes from Lba into Buffer.
537 @param This Indicates a pointer to the calling context.
538 @param MediaId The media ID that the write request is for.
539 @param Lba The starting logical block address to be written. The caller is
540 responsible for writing to only legitimate locations.
541 @param BufferSize Size of Buffer, must be a multiple of device block size.
542 @param Buffer A pointer to the source buffer for the data.
544 @retval EFI_SUCCESS The data was written correctly to the device.
545 @retval EFI_WRITE_PROTECTED The device can not be written to.
546 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
547 @retval EFI_NO_MEDIA There is no media in the device.
548 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
549 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
550 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
551 or the buffer is not on proper alignment.
556 Edd30BiosWriteBlocks (
557 IN EFI_BLOCK_IO_PROTOCOL
*This
,
564 EFI_BLOCK_IO_MEDIA
*Media
;
565 BIOS_BLOCK_IO_DEV
*BiosBlockIoDev
;
566 EDD_DEVICE_ADDRESS_PACKET
*AddressPacket
;
568 // I exist only for readability
570 EFI_IA32_REGISTER_SET Regs
;
571 UINT64 TransferBuffer
;
572 UINTN NumberOfBlocks
;
573 UINTN TransferByteSize
;
575 BIOS_LEGACY_DRIVE
*Bios
;
577 UINTN MaxTransferBlocks
;
578 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
581 BlockSize
= Media
->BlockSize
;
583 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
585 if (MediaId
!= Media
->MediaId
) {
586 return EFI_MEDIA_CHANGED
;
589 if (Lba
> Media
->LastBlock
) {
590 return EFI_DEVICE_ERROR
;
593 if ((Lba
+ (BufferSize
/ BlockSize
) - 1) > Media
->LastBlock
) {
594 return EFI_INVALID_PARAMETER
;
597 if (BufferSize
% BlockSize
!= 0) {
598 return EFI_BAD_BUFFER_SIZE
;
601 if (Buffer
== NULL
) {
602 return EFI_INVALID_PARAMETER
;
605 if (BufferSize
== 0) {
609 BiosBlockIoDev
= BIOS_BLOCK_IO_FROM_THIS (This
);
610 AddressPacket
= mEddBufferUnder1Mb
;
612 MaxTransferBlocks
= MAX_EDD11_XFER
/ BlockSize
;
614 TransferBuffer
= (UINT64
)(UINTN
) Buffer
;
615 for (; BufferSize
> 0;) {
616 NumberOfBlocks
= BufferSize
/ BlockSize
;
617 NumberOfBlocks
= NumberOfBlocks
> MaxTransferBlocks
? MaxTransferBlocks
: NumberOfBlocks
;
619 // Max transfer MaxTransferBlocks
621 AddressPacket
->PacketSizeInBytes
= (UINT8
) sizeof (EDD_DEVICE_ADDRESS_PACKET
);
622 AddressPacket
->Zero
= 0;
623 AddressPacket
->NumberOfBlocks
= (UINT8
) NumberOfBlocks
;
624 AddressPacket
->Zero2
= 0;
625 AddressPacket
->SegOffset
= 0xffffffff;
626 AddressPacket
->Lba
= (UINT64
) Lba
;
627 AddressPacket
->TransferBuffer
= TransferBuffer
;
634 Regs
.H
.DL
= (UINT8
) (BiosBlockIoDev
->Bios
.Number
);
635 Regs
.X
.SI
= EFI_OFFSET (AddressPacket
);
636 Regs
.X
.DS
= EFI_SEGMENT (AddressPacket
);
638 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
641 DEBUG_BLKIO
, "Edd30BiosWriteBlocks: INT 13 43 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev
->Bios
.Number
,
646 Media
->MediaPresent
= TRUE
;
647 if (CarryFlag
!= 0) {
649 // Return Error Status
651 BiosBlockIoDev
->Bios
.ErrorCode
= Regs
.H
.AH
;
652 if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_DISK_CHANGED
) {
654 Bios
= &BiosBlockIoDev
->Bios
;
655 if (Int13GetDeviceParameters (BiosBlockIoDev
, Bios
) != 0) {
656 if (Int13Extensions (BiosBlockIoDev
, Bios
) != 0) {
657 Media
->LastBlock
= (EFI_LBA
) Bios
->Parameters
.PhysicalSectors
- 1;
658 Media
->BlockSize
= (UINT32
) Bios
->Parameters
.BytesPerSector
;
663 Media
->ReadOnly
= FALSE
;
664 gBS
->HandleProtocol (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
665 gBS
->ReinstallProtocolInterface (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, BlockIo
, BlockIo
);
666 return EFI_MEDIA_CHANGED
;
668 } else if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_WRITE_PROTECTED
) {
669 Media
->ReadOnly
= TRUE
;
670 return EFI_WRITE_PROTECTED
;
673 if (Media
->RemovableMedia
) {
674 Media
->MediaPresent
= FALSE
;
677 return EFI_DEVICE_ERROR
;
680 Media
->ReadOnly
= FALSE
;
681 TransferByteSize
= NumberOfBlocks
* BlockSize
;
682 BufferSize
= BufferSize
- TransferByteSize
;
683 TransferBuffer
+= TransferByteSize
;
684 Lba
+= NumberOfBlocks
;
691 Flush the Block Device.
693 @param This Indicates a pointer to the calling context.
695 @retval EFI_SUCCESS All outstanding data was written to the device
696 @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
697 @retval EFI_NO_MEDIA There is no media in the device.
702 BiosBlockIoFlushBlocks (
703 IN EFI_BLOCK_IO_PROTOCOL
*This
710 Reset the Block Device.
712 @param This Indicates a pointer to the calling context.
713 @param ExtendedVerification Driver may perform diagnostics on reset.
715 @retval EFI_SUCCESS The device was reset.
716 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
723 IN EFI_BLOCK_IO_PROTOCOL
*This
,
724 IN BOOLEAN ExtendedVerification
727 BIOS_BLOCK_IO_DEV
*BiosBlockIoDev
;
728 EFI_IA32_REGISTER_SET Regs
;
731 BiosBlockIoDev
= BIOS_BLOCK_IO_FROM_THIS (This
);
733 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
736 Regs
.H
.DL
= BiosBlockIoDev
->Bios
.Number
;
737 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
740 DEBUG_INIT
, "BiosBlockIoReset: INT 13 00 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev
->Bios
.Number
, CarryFlag
,
744 if (CarryFlag
!= 0) {
745 if (Regs
.H
.AL
== BIOS_RESET_FAILED
) {
747 Regs
.H
.DL
= BiosBlockIoDev
->Bios
.Number
;
748 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
751 DEBUG_INIT
, "BiosBlockIoReset: INT 13 00 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev
->Bios
.Number
, CarryFlag
,
755 if (CarryFlag
!= 0) {
756 BiosBlockIoDev
->Bios
.ErrorCode
= Regs
.H
.AH
;
757 return EFI_DEVICE_ERROR
;
766 // These functions need to double buffer all data under 1MB!
771 Read BufferSize bytes from Lba into Buffer.
773 @param This Indicates a pointer to the calling context.
774 @param MediaId Id of the media, changes every time the media is replaced.
775 @param Lba The starting Logical Block Address to read from
776 @param BufferSize Size of Buffer, must be a multiple of device block size.
777 @param Buffer A pointer to the destination buffer for the data. The caller is
778 responsible for either having implicit or explicit ownership of the buffer.
780 @retval EFI_SUCCESS The data was read correctly from the device.
781 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
782 @retval EFI_NO_MEDIA There is no media in the device.
783 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
784 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
785 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
786 or the buffer is not on proper alignment.
791 Edd11BiosReadBlocks (
792 IN EFI_BLOCK_IO_PROTOCOL
*This
,
799 EFI_BLOCK_IO_MEDIA
*Media
;
800 BIOS_BLOCK_IO_DEV
*BiosBlockIoDev
;
801 EDD_DEVICE_ADDRESS_PACKET
*AddressPacket
;
803 // I exist only for readability
805 EFI_IA32_REGISTER_SET Regs
;
806 UINT64 TransferBuffer
;
807 UINTN NumberOfBlocks
;
808 UINTN TransferByteSize
;
810 BIOS_LEGACY_DRIVE
*Bios
;
812 UINTN MaxTransferBlocks
;
813 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
816 BlockSize
= Media
->BlockSize
;
818 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
820 if (MediaId
!= Media
->MediaId
) {
821 return EFI_MEDIA_CHANGED
;
824 if (Lba
> Media
->LastBlock
) {
825 return EFI_INVALID_PARAMETER
;
828 if ((Lba
+ (BufferSize
/ BlockSize
) - 1) > Media
->LastBlock
) {
829 return EFI_INVALID_PARAMETER
;
832 if (BufferSize
% BlockSize
!= 0) {
833 return EFI_BAD_BUFFER_SIZE
;
836 if (Buffer
== NULL
) {
837 return EFI_INVALID_PARAMETER
;
840 if (BufferSize
== 0) {
844 BiosBlockIoDev
= BIOS_BLOCK_IO_FROM_THIS (This
);
845 AddressPacket
= mEddBufferUnder1Mb
;
847 MaxTransferBlocks
= MAX_EDD11_XFER
/ BlockSize
;
849 TransferBuffer
= (UINT64
)(UINTN
) mEdd11Buffer
;
850 for (; BufferSize
> 0;) {
851 NumberOfBlocks
= BufferSize
/ BlockSize
;
852 NumberOfBlocks
= NumberOfBlocks
> MaxTransferBlocks
? MaxTransferBlocks
: NumberOfBlocks
;
854 // Max transfer MaxTransferBlocks
856 AddressPacket
->PacketSizeInBytes
= (UINT8
) sizeof (EDD_DEVICE_ADDRESS_PACKET
);
857 AddressPacket
->Zero
= 0;
858 AddressPacket
->NumberOfBlocks
= (UINT8
) NumberOfBlocks
;
859 AddressPacket
->Zero2
= 0;
861 // TransferBuffer has been 4KB alignment. Normalize TransferBuffer to make offset as 0 in seg:offset
862 // format to transfer maximum 127 blocks of data.
863 // Otherwise when offset adding data size exceeds 0xFFFF, if OpROM does not normalize TransferBuffer,
864 // INT13 function 42H will return data boundary error 09H.
866 AddressPacket
->SegOffset
= (UINT32
) LShiftU64 (RShiftU64(TransferBuffer
, 4), 16);
867 AddressPacket
->Lba
= (UINT64
) Lba
;
870 Regs
.H
.DL
= BiosBlockIoDev
->Bios
.Number
;
871 Regs
.X
.SI
= EFI_OFFSET (AddressPacket
);
872 Regs
.X
.DS
= EFI_SEGMENT (AddressPacket
);
874 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
877 DEBUG_BLKIO
, "Edd11BiosReadBlocks: INT 13 42 DL=%02x : CF=%d AH=%02x : LBA 0x%lx Block(s) %0d \n",
878 BiosBlockIoDev
->Bios
.Number
, CarryFlag
, Regs
.H
.AH
, Lba
, NumberOfBlocks
881 Media
->MediaPresent
= TRUE
;
882 if (CarryFlag
!= 0) {
884 // Return Error Status
886 BiosBlockIoDev
->Bios
.ErrorCode
= Regs
.H
.AH
;
887 if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_DISK_CHANGED
) {
889 Bios
= &BiosBlockIoDev
->Bios
;
890 if (Int13GetDeviceParameters (BiosBlockIoDev
, Bios
) != 0) {
891 if (Int13Extensions (BiosBlockIoDev
, Bios
) != 0) {
892 Media
->LastBlock
= (EFI_LBA
) Bios
->Parameters
.PhysicalSectors
- 1;
893 Media
->BlockSize
= (UINT32
) Bios
->Parameters
.BytesPerSector
;
898 Media
->ReadOnly
= FALSE
;
899 gBS
->HandleProtocol (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
900 gBS
->ReinstallProtocolInterface (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, BlockIo
, BlockIo
);
901 return EFI_MEDIA_CHANGED
;
905 if (Media
->RemovableMedia
) {
906 Media
->MediaPresent
= FALSE
;
909 return EFI_DEVICE_ERROR
;
912 TransferByteSize
= NumberOfBlocks
* BlockSize
;
913 CopyMem (Buffer
, (VOID
*) (UINTN
) TransferBuffer
, TransferByteSize
);
914 BufferSize
= BufferSize
- TransferByteSize
;
915 Buffer
= (VOID
*) ((UINT8
*) Buffer
+ TransferByteSize
);
916 Lba
+= NumberOfBlocks
;
923 Write BufferSize bytes from Lba into Buffer.
925 @param This Indicates a pointer to the calling context.
926 @param MediaId The media ID that the write request is for.
927 @param Lba The starting logical block address to be written. The caller is
928 responsible for writing to only legitimate locations.
929 @param BufferSize Size of Buffer, must be a multiple of device block size.
930 @param Buffer A pointer to the source buffer for the data.
932 @retval EFI_SUCCESS The data was written correctly to the device.
933 @retval EFI_WRITE_PROTECTED The device can not be written to.
934 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
935 @retval EFI_NO_MEDIA There is no media in the device.
936 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
937 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
938 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
939 or the buffer is not on proper alignment.
944 Edd11BiosWriteBlocks (
945 IN EFI_BLOCK_IO_PROTOCOL
*This
,
952 EFI_BLOCK_IO_MEDIA
*Media
;
953 BIOS_BLOCK_IO_DEV
*BiosBlockIoDev
;
954 EDD_DEVICE_ADDRESS_PACKET
*AddressPacket
;
956 // I exist only for readability
958 EFI_IA32_REGISTER_SET Regs
;
959 UINT64 TransferBuffer
;
960 UINTN NumberOfBlocks
;
961 UINTN TransferByteSize
;
963 BIOS_LEGACY_DRIVE
*Bios
;
965 UINTN MaxTransferBlocks
;
966 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
969 BlockSize
= Media
->BlockSize
;
971 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
973 if (MediaId
!= Media
->MediaId
) {
974 return EFI_MEDIA_CHANGED
;
977 if (Lba
> Media
->LastBlock
) {
978 return EFI_INVALID_PARAMETER
;
981 if ((Lba
+ (BufferSize
/ BlockSize
) - 1) > Media
->LastBlock
) {
982 return EFI_INVALID_PARAMETER
;
985 if (BufferSize
% BlockSize
!= 0) {
986 return EFI_BAD_BUFFER_SIZE
;
989 if (Buffer
== NULL
) {
990 return EFI_INVALID_PARAMETER
;
993 if (BufferSize
== 0) {
997 BiosBlockIoDev
= BIOS_BLOCK_IO_FROM_THIS (This
);
998 AddressPacket
= mEddBufferUnder1Mb
;
1000 MaxTransferBlocks
= MAX_EDD11_XFER
/ BlockSize
;
1002 TransferBuffer
= (UINT64
)(UINTN
) mEdd11Buffer
;
1003 for (; BufferSize
> 0;) {
1004 NumberOfBlocks
= BufferSize
/ BlockSize
;
1005 NumberOfBlocks
= NumberOfBlocks
> MaxTransferBlocks
? MaxTransferBlocks
: NumberOfBlocks
;
1007 // Max transfer MaxTransferBlocks
1009 AddressPacket
->PacketSizeInBytes
= (UINT8
) sizeof (EDD_DEVICE_ADDRESS_PACKET
);
1010 AddressPacket
->Zero
= 0;
1011 AddressPacket
->NumberOfBlocks
= (UINT8
) NumberOfBlocks
;
1012 AddressPacket
->Zero2
= 0;
1014 // TransferBuffer has been 4KB alignment. Normalize TransferBuffer to make offset as 0 in seg:offset
1015 // format to transfer maximum 127 blocks of data.
1016 // Otherwise when offset adding data size exceeds 0xFFFF, if OpROM does not normalize TransferBuffer,
1017 // INT13 function 42H will return data boundary error 09H.
1019 AddressPacket
->SegOffset
= (UINT32
) LShiftU64 (RShiftU64(TransferBuffer
, 4), 16);
1020 AddressPacket
->Lba
= (UINT64
) Lba
;
1025 // Write Verify disable
1027 Regs
.H
.DL
= BiosBlockIoDev
->Bios
.Number
;
1028 Regs
.X
.SI
= EFI_OFFSET (AddressPacket
);
1029 Regs
.X
.DS
= EFI_SEGMENT (AddressPacket
);
1031 TransferByteSize
= NumberOfBlocks
* BlockSize
;
1032 CopyMem ((VOID
*) (UINTN
) TransferBuffer
, Buffer
, TransferByteSize
);
1034 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
1037 DEBUG_BLKIO
, "Edd11BiosWriteBlocks: INT 13 43 DL=%02x : CF=%d AH=%02x\n: LBA 0x%lx Block(s) %0d \n",
1038 BiosBlockIoDev
->Bios
.Number
, CarryFlag
, Regs
.H
.AH
, Lba
, NumberOfBlocks
1041 Media
->MediaPresent
= TRUE
;
1042 if (CarryFlag
!= 0) {
1044 // Return Error Status
1046 BiosBlockIoDev
->Bios
.ErrorCode
= Regs
.H
.AH
;
1047 if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_DISK_CHANGED
) {
1049 Bios
= &BiosBlockIoDev
->Bios
;
1050 if (Int13GetDeviceParameters (BiosBlockIoDev
, Bios
) != 0) {
1051 if (Int13Extensions (BiosBlockIoDev
, Bios
) != 0) {
1052 Media
->LastBlock
= (EFI_LBA
) Bios
->Parameters
.PhysicalSectors
- 1;
1053 Media
->BlockSize
= (UINT32
) Bios
->Parameters
.BytesPerSector
;
1058 Media
->ReadOnly
= FALSE
;
1059 gBS
->HandleProtocol (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
1060 gBS
->ReinstallProtocolInterface (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, BlockIo
, BlockIo
);
1061 return EFI_MEDIA_CHANGED
;
1063 } else if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_WRITE_PROTECTED
) {
1064 Media
->ReadOnly
= TRUE
;
1065 return EFI_WRITE_PROTECTED
;
1068 if (Media
->RemovableMedia
) {
1069 Media
->MediaPresent
= FALSE
;
1072 return EFI_DEVICE_ERROR
;
1075 Media
->ReadOnly
= FALSE
;
1076 BufferSize
= BufferSize
- TransferByteSize
;
1077 Buffer
= (VOID
*) ((UINT8
*) Buffer
+ TransferByteSize
);
1078 Lba
+= NumberOfBlocks
;
1085 Read BufferSize bytes from Lba into Buffer.
1087 @param This Indicates a pointer to the calling context.
1088 @param MediaId Id of the media, changes every time the media is replaced.
1089 @param Lba The starting Logical Block Address to read from
1090 @param BufferSize Size of Buffer, must be a multiple of device block size.
1091 @param Buffer A pointer to the destination buffer for the data. The caller is
1092 responsible for either having implicit or explicit ownership of the buffer.
1094 @retval EFI_SUCCESS The data was read correctly from the device.
1095 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
1096 @retval EFI_NO_MEDIA There is no media in the device.
1097 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
1098 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
1099 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
1100 or the buffer is not on proper alignment.
1105 BiosReadLegacyDrive (
1106 IN EFI_BLOCK_IO_PROTOCOL
*This
,
1109 IN UINTN BufferSize
,
1113 EFI_BLOCK_IO_MEDIA
*Media
;
1114 BIOS_BLOCK_IO_DEV
*BiosBlockIoDev
;
1115 EFI_IA32_REGISTER_SET Regs
;
1116 UINTN UpperCylinder
;
1121 UINTN NumberOfBlocks
;
1122 UINTN TransferByteSize
;
1126 BIOS_LEGACY_DRIVE
*Bios
;
1129 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1131 Media
= This
->Media
;
1132 BlockSize
= Media
->BlockSize
;
1134 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
1136 if (MediaId
!= Media
->MediaId
) {
1137 return EFI_MEDIA_CHANGED
;
1140 if (Lba
> Media
->LastBlock
) {
1141 return EFI_INVALID_PARAMETER
;
1144 if ((Lba
+ (BufferSize
/ BlockSize
) - 1) > Media
->LastBlock
) {
1145 return EFI_INVALID_PARAMETER
;
1148 if (BufferSize
% BlockSize
!= 0) {
1149 return EFI_BAD_BUFFER_SIZE
;
1152 if (Buffer
== NULL
) {
1153 return EFI_INVALID_PARAMETER
;
1156 if (BufferSize
== 0) {
1160 BiosBlockIoDev
= BIOS_BLOCK_IO_FROM_THIS (This
);
1161 ShortLba
= (UINTN
) Lba
;
1163 while (BufferSize
!= 0) {
1165 // Compute I/O location in Sector, Head, Cylinder format
1167 Sector
= (ShortLba
% BiosBlockIoDev
->Bios
.MaxSector
) + 1;
1168 Temp
= ShortLba
/ BiosBlockIoDev
->Bios
.MaxSector
;
1169 Head
= Temp
% (BiosBlockIoDev
->Bios
.MaxHead
+ 1);
1170 Cylinder
= Temp
/ (BiosBlockIoDev
->Bios
.MaxHead
+ 1);
1173 // Limit transfer to this Head & Cylinder
1175 NumberOfBlocks
= BufferSize
/ BlockSize
;
1176 Temp
= BiosBlockIoDev
->Bios
.MaxSector
- Sector
+ 1;
1177 NumberOfBlocks
= NumberOfBlocks
> Temp
? Temp
: NumberOfBlocks
;
1185 Regs
.H
.AL
= (UINT8
) NumberOfBlocks
;
1186 Regs
.H
.DL
= BiosBlockIoDev
->Bios
.Number
;
1188 UpperCylinder
= (Cylinder
& 0x0f00) >> 2;
1190 CheckLba
= Cylinder
* (BiosBlockIoDev
->Bios
.MaxHead
+ 1) + Head
;
1191 CheckLba
= CheckLba
* BiosBlockIoDev
->Bios
.MaxSector
+ Sector
- 1;
1195 "RLD: LBA %x (%x), Sector %x (%x), Head %x (%x), Cyl %x, UCyl %x\n",
1199 BiosBlockIoDev
->Bios
.MaxSector
,
1201 BiosBlockIoDev
->Bios
.MaxHead
,
1205 ASSERT (CheckLba
== ShortLba
);
1207 Regs
.H
.CL
= (UINT8
) ((Sector
& 0x3f) + (UpperCylinder
& 0xff));
1208 Regs
.H
.DH
= (UINT8
) (Head
& 0x3f);
1209 Regs
.H
.CH
= (UINT8
) (Cylinder
& 0xff);
1211 Regs
.X
.BX
= EFI_OFFSET (mEdd11Buffer
);
1212 Regs
.X
.ES
= EFI_SEGMENT (mEdd11Buffer
);
1216 "INT 13h: AX:(02%02x) DX:(%02x%02x) CX:(%02x%02x) BX:(%04x) ES:(%04x)\n",
1218 (UINT8
) (Head
& 0x3f),
1220 (UINT8
) (Cylinder
& 0xff),
1221 (UINT8
) ((Sector
& 0x3f) + (UpperCylinder
& 0xff)),
1222 EFI_OFFSET (mEdd11Buffer
),
1223 EFI_SEGMENT (mEdd11Buffer
))
1226 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
1229 DEBUG_BLKIO
, "BiosReadLegacyDrive: INT 13 02 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev
->Bios
.Number
,
1230 CarryFlag
, Regs
.H
.AH
1234 } while (CarryFlag
!= 0 && Retry
!= 0 && Regs
.H
.AH
!= BIOS_DISK_CHANGED
);
1236 Media
->MediaPresent
= TRUE
;
1237 if (CarryFlag
!= 0) {
1239 // Return Error Status
1241 BiosBlockIoDev
->Bios
.ErrorCode
= Regs
.H
.AH
;
1242 if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_DISK_CHANGED
) {
1244 Bios
= &BiosBlockIoDev
->Bios
;
1245 if (Int13GetDeviceParameters (BiosBlockIoDev
, Bios
) != 0) {
1247 // If the size of the media changed we need to reset the disk geometry
1249 if (Int13Extensions (BiosBlockIoDev
, Bios
) != 0) {
1250 Media
->LastBlock
= (EFI_LBA
) Bios
->Parameters
.PhysicalSectors
- 1;
1251 Media
->BlockSize
= (UINT32
) Bios
->Parameters
.BytesPerSector
;
1254 // Legacy Interfaces
1256 Media
->LastBlock
= (Bios
->MaxHead
+ 1) * Bios
->MaxSector
* (Bios
->MaxCylinder
+ 1) - 1;
1257 Media
->BlockSize
= 512;
1260 Media
->ReadOnly
= FALSE
;
1261 gBS
->HandleProtocol (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
1262 gBS
->ReinstallProtocolInterface (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, BlockIo
, BlockIo
);
1263 return EFI_MEDIA_CHANGED
;
1267 if (Media
->RemovableMedia
) {
1268 Media
->MediaPresent
= FALSE
;
1271 return EFI_DEVICE_ERROR
;
1274 TransferByteSize
= NumberOfBlocks
* BlockSize
;
1275 CopyMem (Buffer
, mEdd11Buffer
, TransferByteSize
);
1277 ShortLba
= ShortLba
+ NumberOfBlocks
;
1278 BufferSize
= BufferSize
- TransferByteSize
;
1279 Buffer
= (VOID
*) ((UINT8
*) Buffer
+ TransferByteSize
);
1286 Write BufferSize bytes from Lba into Buffer.
1288 @param This Indicates a pointer to the calling context.
1289 @param MediaId The media ID that the write request is for.
1290 @param Lba The starting logical block address to be written. The caller is
1291 responsible for writing to only legitimate locations.
1292 @param BufferSize Size of Buffer, must be a multiple of device block size.
1293 @param Buffer A pointer to the source buffer for the data.
1295 @retval EFI_SUCCESS The data was written correctly to the device.
1296 @retval EFI_WRITE_PROTECTED The device can not be written to.
1297 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
1298 @retval EFI_NO_MEDIA There is no media in the device.
1299 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
1300 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
1301 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
1302 or the buffer is not on proper alignment.
1307 BiosWriteLegacyDrive (
1308 IN EFI_BLOCK_IO_PROTOCOL
*This
,
1311 IN UINTN BufferSize
,
1315 EFI_BLOCK_IO_MEDIA
*Media
;
1316 BIOS_BLOCK_IO_DEV
*BiosBlockIoDev
;
1317 EFI_IA32_REGISTER_SET Regs
;
1318 UINTN UpperCylinder
;
1323 UINTN NumberOfBlocks
;
1324 UINTN TransferByteSize
;
1328 BIOS_LEGACY_DRIVE
*Bios
;
1331 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1333 Media
= This
->Media
;
1334 BlockSize
= Media
->BlockSize
;
1336 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
1338 if (MediaId
!= Media
->MediaId
) {
1339 return EFI_MEDIA_CHANGED
;
1342 if (Lba
> Media
->LastBlock
) {
1343 return EFI_INVALID_PARAMETER
;
1346 if ((Lba
+ (BufferSize
/ BlockSize
) - 1) > Media
->LastBlock
) {
1347 return EFI_INVALID_PARAMETER
;
1350 if (BufferSize
% BlockSize
!= 0) {
1351 return EFI_BAD_BUFFER_SIZE
;
1354 if (Buffer
== NULL
) {
1355 return EFI_INVALID_PARAMETER
;
1358 if (BufferSize
== 0) {
1362 BiosBlockIoDev
= BIOS_BLOCK_IO_FROM_THIS (This
);
1363 ShortLba
= (UINTN
) Lba
;
1365 while (BufferSize
!= 0) {
1367 // Compute I/O location in Sector, Head, Cylinder format
1369 Sector
= (ShortLba
% BiosBlockIoDev
->Bios
.MaxSector
) + 1;
1370 Temp
= ShortLba
/ BiosBlockIoDev
->Bios
.MaxSector
;
1371 Head
= Temp
% (BiosBlockIoDev
->Bios
.MaxHead
+ 1);
1372 Cylinder
= Temp
/ (BiosBlockIoDev
->Bios
.MaxHead
+ 1);
1375 // Limit transfer to this Head & Cylinder
1377 NumberOfBlocks
= BufferSize
/ BlockSize
;
1378 Temp
= BiosBlockIoDev
->Bios
.MaxSector
- Sector
+ 1;
1379 NumberOfBlocks
= NumberOfBlocks
> Temp
? Temp
: NumberOfBlocks
;
1387 Regs
.H
.AL
= (UINT8
) NumberOfBlocks
;
1388 Regs
.H
.DL
= BiosBlockIoDev
->Bios
.Number
;
1390 UpperCylinder
= (Cylinder
& 0x0f00) >> 2;
1392 CheckLba
= Cylinder
* (BiosBlockIoDev
->Bios
.MaxHead
+ 1) + Head
;
1393 CheckLba
= CheckLba
* BiosBlockIoDev
->Bios
.MaxSector
+ Sector
- 1;
1397 "RLD: LBA %x (%x), Sector %x (%x), Head %x (%x), Cyl %x, UCyl %x\n",
1401 BiosBlockIoDev
->Bios
.MaxSector
,
1403 BiosBlockIoDev
->Bios
.MaxHead
,
1407 ASSERT (CheckLba
== ShortLba
);
1409 Regs
.H
.CL
= (UINT8
) ((Sector
& 0x3f) + (UpperCylinder
& 0xff));
1410 Regs
.H
.DH
= (UINT8
) (Head
& 0x3f);
1411 Regs
.H
.CH
= (UINT8
) (Cylinder
& 0xff);
1413 Regs
.X
.BX
= EFI_OFFSET (mEdd11Buffer
);
1414 Regs
.X
.ES
= EFI_SEGMENT (mEdd11Buffer
);
1416 TransferByteSize
= NumberOfBlocks
* BlockSize
;
1417 CopyMem (mEdd11Buffer
, Buffer
, TransferByteSize
);
1421 "INT 13h: AX:(03%02x) DX:(%02x%02x) CX:(%02x%02x) BX:(%04x) ES:(%04x)\n",
1423 (UINT8
) (Head
& 0x3f),
1425 (UINT8
) (Cylinder
& 0xff),
1426 (UINT8
) ((Sector
& 0x3f) + (UpperCylinder
& 0xff)),
1427 EFI_OFFSET (mEdd11Buffer
),
1428 EFI_SEGMENT (mEdd11Buffer
))
1431 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
1434 DEBUG_BLKIO
, "BiosWriteLegacyDrive: INT 13 03 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev
->Bios
.Number
,
1435 CarryFlag
, Regs
.H
.AH
1439 } while (CarryFlag
!= 0 && Retry
!= 0 && Regs
.H
.AH
!= BIOS_DISK_CHANGED
);
1441 Media
->MediaPresent
= TRUE
;
1442 if (CarryFlag
!= 0) {
1444 // Return Error Status
1446 BiosBlockIoDev
->Bios
.ErrorCode
= Regs
.H
.AH
;
1447 if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_DISK_CHANGED
) {
1449 Bios
= &BiosBlockIoDev
->Bios
;
1450 if (Int13GetDeviceParameters (BiosBlockIoDev
, Bios
) != 0) {
1451 if (Int13Extensions (BiosBlockIoDev
, Bios
) != 0) {
1452 Media
->LastBlock
= (EFI_LBA
) Bios
->Parameters
.PhysicalSectors
- 1;
1453 Media
->BlockSize
= (UINT32
) Bios
->Parameters
.BytesPerSector
;
1456 // Legacy Interfaces
1458 Media
->LastBlock
= (Bios
->MaxHead
+ 1) * Bios
->MaxSector
* (Bios
->MaxCylinder
+ 1) - 1;
1459 Media
->BlockSize
= 512;
1462 // If the size of the media changed we need to reset the disk geometry
1464 Media
->ReadOnly
= FALSE
;
1465 gBS
->HandleProtocol (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
1466 gBS
->ReinstallProtocolInterface (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, BlockIo
, BlockIo
);
1467 return EFI_MEDIA_CHANGED
;
1469 } else if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_WRITE_PROTECTED
) {
1470 Media
->ReadOnly
= TRUE
;
1471 return EFI_WRITE_PROTECTED
;
1474 if (Media
->RemovableMedia
) {
1475 Media
->MediaPresent
= FALSE
;
1478 return EFI_DEVICE_ERROR
;
1481 Media
->ReadOnly
= FALSE
;
1482 ShortLba
= ShortLba
+ NumberOfBlocks
;
1483 BufferSize
= BufferSize
- TransferByteSize
;
1484 Buffer
= (VOID
*) ((UINT8
*) Buffer
+ TransferByteSize
);