2 Routines that use BIOS to support INT 13 devices.
4 Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>
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
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.
17 #include "BiosBlkIo.h"
20 // Module global variables
23 // Address packet is a buffer under 1 MB for all version EDD calls
25 extern EDD_DEVICE_ADDRESS_PACKET
*mEddBufferUnder1Mb
;
28 // This is a buffer for INT 13h func 48 information
30 extern BIOS_LEGACY_DRIVE
*mLegacyDriverUnder1Mb
;
33 // Buffer of 0xFE00 bytes for EDD 1.1 transfer must be under 1 MB
34 // 0xFE00 bytes is the max transfer size supported.
36 extern VOID
*mEdd11Buffer
;
40 Initialize block I/O device instance
42 @param Dev Instance of block I/O device instance
44 @retval TRUE Initialization succeeds.
45 @retval FALSE Initialization fails.
50 IN BIOS_BLOCK_IO_DEV
*Dev
53 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
54 EFI_BLOCK_IO_MEDIA
*BlockMedia
;
55 BIOS_LEGACY_DRIVE
*Bios
;
57 BlockIo
= &Dev
->BlockIo
;
58 BlockIo
->Media
= &Dev
->BlockMedia
;
59 BlockMedia
= BlockIo
->Media
;
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
;
67 if ((Bios
->Parameters
.Flags
& EDD_DEVICE_REMOVABLE
) == EDD_DEVICE_REMOVABLE
) {
68 BlockMedia
->RemovableMedia
= TRUE
;
75 BlockMedia
->BlockSize
= 512;
76 BlockMedia
->LastBlock
= (Bios
->MaxHead
+ 1) * Bios
->MaxSector
* (Bios
->MaxCylinder
+ 1) - 1;
79 DEBUG ((DEBUG_INIT
, "BlockSize = %d LastBlock = %d\n", BlockMedia
->BlockSize
, BlockMedia
->LastBlock
));
81 BlockMedia
->LogicalPartition
= FALSE
;
82 BlockMedia
->WriteCaching
= FALSE
;
85 // BugBug: Need to set this for removable media devices if they do not
88 BlockMedia
->ReadOnly
= FALSE
;
89 BlockMedia
->MediaPresent
= TRUE
;
91 BlockIo
->Reset
= BiosBlockIoReset
;
92 BlockIo
->FlushBlocks
= BiosBlockIoFlushBlocks
;
94 if (!Bios
->ExtendedInt13
) {
98 BlockIo
->ReadBlocks
= BiosReadLegacyDrive
;
99 BlockIo
->WriteBlocks
= BiosWriteLegacyDrive
;
100 } else if ((Bios
->EddVersion
== EDD_VERSION_30
) && (Bios
->Extensions64Bit
)) {
102 // EDD 3.0 Required for Device path, but extended reads are not required.
104 BlockIo
->ReadBlocks
= Edd30BiosReadBlocks
;
105 BlockIo
->WriteBlocks
= Edd30BiosWriteBlocks
;
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.
113 BlockIo
->ReadBlocks
= Edd11BiosReadBlocks
;
114 BlockIo
->WriteBlocks
= Edd11BiosWriteBlocks
;
117 BlockMedia
->LogicalPartition
= FALSE
;
118 BlockMedia
->WriteCaching
= FALSE
;
127 Gets parameters of block I/O device.
129 @param BiosBlockIoDev Instance of block I/O device.
130 @param Drive Legacy drive.
132 @return Result of device parameter retrieval.
136 Int13GetDeviceParameters (
137 IN BIOS_BLOCK_IO_DEV
*BiosBlockIoDev
,
138 IN BIOS_LEGACY_DRIVE
*Drive
143 EFI_IA32_REGISTER_SET Regs
;
145 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
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
;
157 if (Regs
.H
.BL
== 0x10) {
158 Drive
->AtapiFloppy
= TRUE
;
160 Drive
->MaxHead
= Regs
.H
.DH
;
161 Drive
->MaxSector
= Regs
.H
.CL
;
162 Drive
->MaxCylinder
= Regs
.H
.CH
;
163 if (Drive
->MaxSector
== 0) {
165 // BugBug: You can not trust the Carry flag.
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);
182 Extension of INT13 call.
184 @param BiosBlockIoDev Instance of block I/O device.
185 @param Drive Legacy drive.
187 @return Result of this extension.
192 IN BIOS_BLOCK_IO_DEV
*BiosBlockIoDev
,
193 IN BIOS_LEGACY_DRIVE
*Drive
197 EFI_IA32_REGISTER_SET Regs
;
199 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
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
;
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);
219 Drive
->ParametersValid
= (UINT8
) GetDriveParameters (BiosBlockIoDev
, Drive
);
224 Gets parameters of legacy drive.
226 @param BiosBlockIoDev Instance of block I/O device.
227 @param Drive Legacy drive.
229 @return Result of drive parameter retrieval.
234 IN BIOS_BLOCK_IO_DEV
*BiosBlockIoDev
,
235 IN BIOS_LEGACY_DRIVE
*Drive
239 EFI_IA32_REGISTER_SET Regs
;
242 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
245 Regs
.H
.DL
= Drive
->Number
;
248 // EDD Buffer must be passed in with max buffer size as first entry in the buffer
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);
261 // We only have one buffer < 1MB, so copy into our instance data
265 &mLegacyDriverUnder1Mb
->Parameters
,
266 sizeof (Drive
->Parameters
)
269 if (Drive
->AtapiFloppy
) {
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) {
279 // Media not present or unknown media present
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);
288 Drive
->MaxSector
= 1;
289 Drive
->MaxCylinder
= 0;
302 Drive
->MaxSector
= 9;
303 Drive
->MaxCylinder
= 79;
311 Drive
->MaxSector
= 18;
312 Drive
->MaxCylinder
= 79;
320 Drive
->MaxSector
= 36;
321 Drive
->MaxCylinder
= 79;
329 Drive
->MaxSector
= 9;
330 Drive
->MaxCylinder
= 39;
338 Drive
->MaxSector
= 15;
339 Drive
->MaxCylinder
= 79;
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);
361 Drive
->MaxSector
= 1;
362 Drive
->MaxCylinder
= 0;
368 // Unknown media type.
371 Drive
->MaxSector
= 1;
372 Drive
->MaxCylinder
= 0;
377 Drive
->Parameters
.PhysicalSectors
= (Drive
->MaxHead
+ 1) * Drive
->MaxSector
* (Drive
->MaxCylinder
+ 1);
378 Drive
->Parameters
.BytesPerSector
= 512;
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
384 PointerMath
= EFI_SEGMENT (Drive
->Parameters
.Fdpt
) << 4;
385 PointerMath
+= EFI_OFFSET (Drive
->Parameters
.Fdpt
);
386 Drive
->FdptPointer
= (VOID
*) PointerMath
;
395 Read BufferSize bytes from Lba into Buffer.
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.
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.
415 Edd30BiosReadBlocks (
416 IN EFI_BLOCK_IO_PROTOCOL
*This
,
423 EFI_BLOCK_IO_MEDIA
*Media
;
424 BIOS_BLOCK_IO_DEV
*BiosBlockIoDev
;
425 EDD_DEVICE_ADDRESS_PACKET
*AddressPacket
;
427 // I exist only for readability
429 EFI_IA32_REGISTER_SET Regs
;
430 UINT64 TransferBuffer
;
431 UINTN NumberOfBlocks
;
432 UINTN TransferByteSize
;
434 BIOS_LEGACY_DRIVE
*Bios
;
436 UINTN MaxTransferBlocks
;
437 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
440 BlockSize
= Media
->BlockSize
;
442 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
444 if (MediaId
!= Media
->MediaId
) {
445 return EFI_MEDIA_CHANGED
;
448 if (Lba
> Media
->LastBlock
) {
449 return EFI_INVALID_PARAMETER
;
452 if ((Lba
+ (BufferSize
/ BlockSize
) - 1) > Media
->LastBlock
) {
453 return EFI_INVALID_PARAMETER
;
456 if (BufferSize
% BlockSize
!= 0) {
457 return EFI_BAD_BUFFER_SIZE
;
460 if (Buffer
== NULL
) {
461 return EFI_INVALID_PARAMETER
;
464 if (BufferSize
== 0) {
468 BiosBlockIoDev
= BIOS_BLOCK_IO_FROM_THIS (This
);
469 AddressPacket
= mEddBufferUnder1Mb
;
471 MaxTransferBlocks
= MAX_EDD11_XFER
/ BlockSize
;
473 TransferBuffer
= (UINT64
)(UINTN
) Buffer
;
474 for (; BufferSize
> 0;) {
475 NumberOfBlocks
= BufferSize
/ BlockSize
;
476 NumberOfBlocks
= NumberOfBlocks
> MaxTransferBlocks
? MaxTransferBlocks
: NumberOfBlocks
;
478 // Max transfer MaxTransferBlocks
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
;
489 Regs
.H
.DL
= BiosBlockIoDev
->Bios
.Number
;
490 Regs
.X
.SI
= EFI_OFFSET (AddressPacket
);
491 Regs
.X
.DS
= EFI_SEGMENT (AddressPacket
);
493 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
496 DEBUG_BLKIO
, "Edd30BiosReadBlocks: INT 13 42 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev
->Bios
.Number
,
501 Media
->MediaPresent
= TRUE
;
502 if (CarryFlag
!= 0) {
504 // Return Error Status
506 BiosBlockIoDev
->Bios
.ErrorCode
= Regs
.H
.AH
;
507 if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_DISK_CHANGED
) {
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
;
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
;
525 if (Media
->RemovableMedia
) {
526 Media
->MediaPresent
= FALSE
;
529 return EFI_DEVICE_ERROR
;
532 TransferByteSize
= NumberOfBlocks
* BlockSize
;
533 BufferSize
= BufferSize
- TransferByteSize
;
534 TransferBuffer
+= TransferByteSize
;
535 Lba
+= NumberOfBlocks
;
542 Write BufferSize bytes from Lba into Buffer.
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.
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.
563 Edd30BiosWriteBlocks (
564 IN EFI_BLOCK_IO_PROTOCOL
*This
,
571 EFI_BLOCK_IO_MEDIA
*Media
;
572 BIOS_BLOCK_IO_DEV
*BiosBlockIoDev
;
573 EDD_DEVICE_ADDRESS_PACKET
*AddressPacket
;
575 // I exist only for readability
577 EFI_IA32_REGISTER_SET Regs
;
578 UINT64 TransferBuffer
;
579 UINTN NumberOfBlocks
;
580 UINTN TransferByteSize
;
582 BIOS_LEGACY_DRIVE
*Bios
;
584 UINTN MaxTransferBlocks
;
585 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
588 BlockSize
= Media
->BlockSize
;
590 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
592 if (MediaId
!= Media
->MediaId
) {
593 return EFI_MEDIA_CHANGED
;
596 if (Lba
> Media
->LastBlock
) {
597 return EFI_DEVICE_ERROR
;
600 if ((Lba
+ (BufferSize
/ BlockSize
) - 1) > Media
->LastBlock
) {
601 return EFI_INVALID_PARAMETER
;
604 if (BufferSize
% BlockSize
!= 0) {
605 return EFI_BAD_BUFFER_SIZE
;
608 if (Buffer
== NULL
) {
609 return EFI_INVALID_PARAMETER
;
612 if (BufferSize
== 0) {
616 BiosBlockIoDev
= BIOS_BLOCK_IO_FROM_THIS (This
);
617 AddressPacket
= mEddBufferUnder1Mb
;
619 MaxTransferBlocks
= MAX_EDD11_XFER
/ BlockSize
;
621 TransferBuffer
= (UINT64
)(UINTN
) Buffer
;
622 for (; BufferSize
> 0;) {
623 NumberOfBlocks
= BufferSize
/ BlockSize
;
624 NumberOfBlocks
= NumberOfBlocks
> MaxTransferBlocks
? MaxTransferBlocks
: NumberOfBlocks
;
626 // Max transfer MaxTransferBlocks
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
;
641 Regs
.H
.DL
= (UINT8
) (BiosBlockIoDev
->Bios
.Number
);
642 Regs
.X
.SI
= EFI_OFFSET (AddressPacket
);
643 Regs
.X
.DS
= EFI_SEGMENT (AddressPacket
);
645 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
648 DEBUG_BLKIO
, "Edd30BiosWriteBlocks: INT 13 43 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev
->Bios
.Number
,
653 Media
->MediaPresent
= TRUE
;
654 if (CarryFlag
!= 0) {
656 // Return Error Status
658 BiosBlockIoDev
->Bios
.ErrorCode
= Regs
.H
.AH
;
659 if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_DISK_CHANGED
) {
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
;
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
;
675 } else if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_WRITE_PROTECTED
) {
676 Media
->ReadOnly
= TRUE
;
677 return EFI_WRITE_PROTECTED
;
680 if (Media
->RemovableMedia
) {
681 Media
->MediaPresent
= FALSE
;
684 return EFI_DEVICE_ERROR
;
687 Media
->ReadOnly
= FALSE
;
688 TransferByteSize
= NumberOfBlocks
* BlockSize
;
689 BufferSize
= BufferSize
- TransferByteSize
;
690 TransferBuffer
+= TransferByteSize
;
691 Lba
+= NumberOfBlocks
;
698 Flush the Block Device.
700 @param This Indicates a pointer to the calling context.
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.
709 BiosBlockIoFlushBlocks (
710 IN EFI_BLOCK_IO_PROTOCOL
*This
717 Reset the Block Device.
719 @param This Indicates a pointer to the calling context.
720 @param ExtendedVerification Driver may perform diagnostics on reset.
722 @retval EFI_SUCCESS The device was reset.
723 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
730 IN EFI_BLOCK_IO_PROTOCOL
*This
,
731 IN BOOLEAN ExtendedVerification
734 BIOS_BLOCK_IO_DEV
*BiosBlockIoDev
;
735 EFI_IA32_REGISTER_SET Regs
;
738 BiosBlockIoDev
= BIOS_BLOCK_IO_FROM_THIS (This
);
740 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
743 Regs
.H
.DL
= BiosBlockIoDev
->Bios
.Number
;
744 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
747 DEBUG_INIT
, "BiosBlockIoReset: INT 13 00 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev
->Bios
.Number
, CarryFlag
,
751 if (CarryFlag
!= 0) {
752 if (Regs
.H
.AL
== BIOS_RESET_FAILED
) {
754 Regs
.H
.DL
= BiosBlockIoDev
->Bios
.Number
;
755 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
758 DEBUG_INIT
, "BiosBlockIoReset: INT 13 00 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev
->Bios
.Number
, CarryFlag
,
762 if (CarryFlag
!= 0) {
763 BiosBlockIoDev
->Bios
.ErrorCode
= Regs
.H
.AH
;
764 return EFI_DEVICE_ERROR
;
773 // These functions need to double buffer all data under 1MB!
778 Read BufferSize bytes from Lba into Buffer.
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.
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.
798 Edd11BiosReadBlocks (
799 IN EFI_BLOCK_IO_PROTOCOL
*This
,
806 EFI_BLOCK_IO_MEDIA
*Media
;
807 BIOS_BLOCK_IO_DEV
*BiosBlockIoDev
;
808 EDD_DEVICE_ADDRESS_PACKET
*AddressPacket
;
810 // I exist only for readability
812 EFI_IA32_REGISTER_SET Regs
;
813 UINT64 TransferBuffer
;
814 UINTN NumberOfBlocks
;
815 UINTN TransferByteSize
;
817 BIOS_LEGACY_DRIVE
*Bios
;
819 UINTN MaxTransferBlocks
;
820 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
823 BlockSize
= Media
->BlockSize
;
825 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
827 if (MediaId
!= Media
->MediaId
) {
828 return EFI_MEDIA_CHANGED
;
831 if (Lba
> Media
->LastBlock
) {
832 return EFI_INVALID_PARAMETER
;
835 if ((Lba
+ (BufferSize
/ BlockSize
) - 1) > Media
->LastBlock
) {
836 return EFI_INVALID_PARAMETER
;
839 if (BufferSize
% BlockSize
!= 0) {
840 return EFI_BAD_BUFFER_SIZE
;
843 if (Buffer
== NULL
) {
844 return EFI_INVALID_PARAMETER
;
847 if (BufferSize
== 0) {
851 BiosBlockIoDev
= BIOS_BLOCK_IO_FROM_THIS (This
);
852 AddressPacket
= mEddBufferUnder1Mb
;
854 MaxTransferBlocks
= MAX_EDD11_XFER
/ BlockSize
;
856 TransferBuffer
= (UINT64
)(UINTN
) mEdd11Buffer
;
857 for (; BufferSize
> 0;) {
858 NumberOfBlocks
= BufferSize
/ BlockSize
;
859 NumberOfBlocks
= NumberOfBlocks
> MaxTransferBlocks
? MaxTransferBlocks
: NumberOfBlocks
;
861 // Max transfer MaxTransferBlocks
863 AddressPacket
->PacketSizeInBytes
= (UINT8
) sizeof (EDD_DEVICE_ADDRESS_PACKET
);
864 AddressPacket
->Zero
= 0;
865 AddressPacket
->NumberOfBlocks
= (UINT8
) NumberOfBlocks
;
866 AddressPacket
->Zero2
= 0;
867 AddressPacket
->SegOffset
= EFI_SEGMENT (TransferBuffer
) << 16;
868 AddressPacket
->SegOffset
|= EFI_OFFSET (TransferBuffer
);
869 AddressPacket
->Lba
= (UINT64
) Lba
;
872 Regs
.H
.DL
= BiosBlockIoDev
->Bios
.Number
;
873 Regs
.X
.SI
= EFI_OFFSET (AddressPacket
);
874 Regs
.X
.DS
= EFI_SEGMENT (AddressPacket
);
876 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
879 DEBUG_BLKIO
, "Edd11BiosReadBlocks: INT 13 42 DL=%02x : CF=%d AH=%02x : LBA 0x%lx Block(s) %0d \n",
880 BiosBlockIoDev
->Bios
.Number
, CarryFlag
, Regs
.H
.AH
, Lba
, NumberOfBlocks
883 Media
->MediaPresent
= TRUE
;
884 if (CarryFlag
!= 0) {
886 // Return Error Status
888 BiosBlockIoDev
->Bios
.ErrorCode
= Regs
.H
.AH
;
889 if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_DISK_CHANGED
) {
891 Bios
= &BiosBlockIoDev
->Bios
;
892 if (Int13GetDeviceParameters (BiosBlockIoDev
, Bios
) != 0) {
893 if (Int13Extensions (BiosBlockIoDev
, Bios
) != 0) {
894 Media
->LastBlock
= (EFI_LBA
) Bios
->Parameters
.PhysicalSectors
- 1;
895 Media
->BlockSize
= (UINT32
) Bios
->Parameters
.BytesPerSector
;
900 Media
->ReadOnly
= FALSE
;
901 gBS
->HandleProtocol (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
902 gBS
->ReinstallProtocolInterface (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, BlockIo
, BlockIo
);
903 return EFI_MEDIA_CHANGED
;
907 if (Media
->RemovableMedia
) {
908 Media
->MediaPresent
= FALSE
;
911 return EFI_DEVICE_ERROR
;
914 TransferByteSize
= NumberOfBlocks
* BlockSize
;
915 CopyMem (Buffer
, (VOID
*) (UINTN
) TransferBuffer
, TransferByteSize
);
916 BufferSize
= BufferSize
- TransferByteSize
;
917 Buffer
= (VOID
*) ((UINT8
*) Buffer
+ TransferByteSize
);
918 Lba
+= NumberOfBlocks
;
925 Write BufferSize bytes from Lba into Buffer.
927 @param This Indicates a pointer to the calling context.
928 @param MediaId The media ID that the write request is for.
929 @param Lba The starting logical block address to be written. The caller is
930 responsible for writing to only legitimate locations.
931 @param BufferSize Size of Buffer, must be a multiple of device block size.
932 @param Buffer A pointer to the source buffer for the data.
934 @retval EFI_SUCCESS The data was written correctly to the device.
935 @retval EFI_WRITE_PROTECTED The device can not be written to.
936 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
937 @retval EFI_NO_MEDIA There is no media in the device.
938 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
939 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
940 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
941 or the buffer is not on proper alignment.
946 Edd11BiosWriteBlocks (
947 IN EFI_BLOCK_IO_PROTOCOL
*This
,
954 EFI_BLOCK_IO_MEDIA
*Media
;
955 BIOS_BLOCK_IO_DEV
*BiosBlockIoDev
;
956 EDD_DEVICE_ADDRESS_PACKET
*AddressPacket
;
958 // I exist only for readability
960 EFI_IA32_REGISTER_SET Regs
;
961 UINT64 TransferBuffer
;
962 UINTN NumberOfBlocks
;
963 UINTN TransferByteSize
;
965 BIOS_LEGACY_DRIVE
*Bios
;
967 UINTN MaxTransferBlocks
;
968 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
971 BlockSize
= Media
->BlockSize
;
973 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
975 if (MediaId
!= Media
->MediaId
) {
976 return EFI_MEDIA_CHANGED
;
979 if (Lba
> Media
->LastBlock
) {
980 return EFI_INVALID_PARAMETER
;
983 if ((Lba
+ (BufferSize
/ BlockSize
) - 1) > Media
->LastBlock
) {
984 return EFI_INVALID_PARAMETER
;
987 if (BufferSize
% BlockSize
!= 0) {
988 return EFI_BAD_BUFFER_SIZE
;
991 if (Buffer
== NULL
) {
992 return EFI_INVALID_PARAMETER
;
995 if (BufferSize
== 0) {
999 BiosBlockIoDev
= BIOS_BLOCK_IO_FROM_THIS (This
);
1000 AddressPacket
= mEddBufferUnder1Mb
;
1002 MaxTransferBlocks
= MAX_EDD11_XFER
/ BlockSize
;
1004 TransferBuffer
= (UINT64
)(UINTN
) mEdd11Buffer
;
1005 for (; BufferSize
> 0;) {
1006 NumberOfBlocks
= BufferSize
/ BlockSize
;
1007 NumberOfBlocks
= NumberOfBlocks
> MaxTransferBlocks
? MaxTransferBlocks
: NumberOfBlocks
;
1009 // Max transfer MaxTransferBlocks
1011 AddressPacket
->PacketSizeInBytes
= (UINT8
) sizeof (EDD_DEVICE_ADDRESS_PACKET
);
1012 AddressPacket
->Zero
= 0;
1013 AddressPacket
->NumberOfBlocks
= (UINT8
) NumberOfBlocks
;
1014 AddressPacket
->Zero2
= 0;
1015 AddressPacket
->SegOffset
= EFI_SEGMENT (TransferBuffer
) << 16;
1016 AddressPacket
->SegOffset
|= EFI_OFFSET (TransferBuffer
);
1017 AddressPacket
->Lba
= (UINT64
) Lba
;
1022 // Write Verify disable
1024 Regs
.H
.DL
= BiosBlockIoDev
->Bios
.Number
;
1025 Regs
.X
.SI
= EFI_OFFSET (AddressPacket
);
1026 Regs
.X
.DS
= EFI_SEGMENT (AddressPacket
);
1028 TransferByteSize
= NumberOfBlocks
* BlockSize
;
1029 CopyMem ((VOID
*) (UINTN
) TransferBuffer
, Buffer
, TransferByteSize
);
1031 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
1034 DEBUG_BLKIO
, "Edd11BiosWriteBlocks: INT 13 43 DL=%02x : CF=%d AH=%02x\n: LBA 0x%lx Block(s) %0d \n",
1035 BiosBlockIoDev
->Bios
.Number
, CarryFlag
, Regs
.H
.AH
, Lba
, NumberOfBlocks
1038 Media
->MediaPresent
= TRUE
;
1039 if (CarryFlag
!= 0) {
1041 // Return Error Status
1043 BiosBlockIoDev
->Bios
.ErrorCode
= Regs
.H
.AH
;
1044 if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_DISK_CHANGED
) {
1046 Bios
= &BiosBlockIoDev
->Bios
;
1047 if (Int13GetDeviceParameters (BiosBlockIoDev
, Bios
) != 0) {
1048 if (Int13Extensions (BiosBlockIoDev
, Bios
) != 0) {
1049 Media
->LastBlock
= (EFI_LBA
) Bios
->Parameters
.PhysicalSectors
- 1;
1050 Media
->BlockSize
= (UINT32
) Bios
->Parameters
.BytesPerSector
;
1055 Media
->ReadOnly
= FALSE
;
1056 gBS
->HandleProtocol (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
1057 gBS
->ReinstallProtocolInterface (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, BlockIo
, BlockIo
);
1058 return EFI_MEDIA_CHANGED
;
1060 } else if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_WRITE_PROTECTED
) {
1061 Media
->ReadOnly
= TRUE
;
1062 return EFI_WRITE_PROTECTED
;
1065 if (Media
->RemovableMedia
) {
1066 Media
->MediaPresent
= FALSE
;
1069 return EFI_DEVICE_ERROR
;
1072 Media
->ReadOnly
= FALSE
;
1073 BufferSize
= BufferSize
- TransferByteSize
;
1074 Buffer
= (VOID
*) ((UINT8
*) Buffer
+ TransferByteSize
);
1075 Lba
+= NumberOfBlocks
;
1082 Read BufferSize bytes from Lba into Buffer.
1084 @param This Indicates a pointer to the calling context.
1085 @param MediaId Id of the media, changes every time the media is replaced.
1086 @param Lba The starting Logical Block Address to read from
1087 @param BufferSize Size of Buffer, must be a multiple of device block size.
1088 @param Buffer A pointer to the destination buffer for the data. The caller is
1089 responsible for either having implicit or explicit ownership of the buffer.
1091 @retval EFI_SUCCESS The data was read correctly from the device.
1092 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
1093 @retval EFI_NO_MEDIA There is no media in the device.
1094 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
1095 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
1096 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
1097 or the buffer is not on proper alignment.
1102 BiosReadLegacyDrive (
1103 IN EFI_BLOCK_IO_PROTOCOL
*This
,
1106 IN UINTN BufferSize
,
1110 EFI_BLOCK_IO_MEDIA
*Media
;
1111 BIOS_BLOCK_IO_DEV
*BiosBlockIoDev
;
1112 EFI_IA32_REGISTER_SET Regs
;
1113 UINTN UpperCylinder
;
1118 UINTN NumberOfBlocks
;
1119 UINTN TransferByteSize
;
1123 BIOS_LEGACY_DRIVE
*Bios
;
1126 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1128 Media
= This
->Media
;
1129 BlockSize
= Media
->BlockSize
;
1131 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
1133 if (MediaId
!= Media
->MediaId
) {
1134 return EFI_MEDIA_CHANGED
;
1137 if (Lba
> Media
->LastBlock
) {
1138 return EFI_INVALID_PARAMETER
;
1141 if ((Lba
+ (BufferSize
/ BlockSize
) - 1) > Media
->LastBlock
) {
1142 return EFI_INVALID_PARAMETER
;
1145 if (BufferSize
% BlockSize
!= 0) {
1146 return EFI_BAD_BUFFER_SIZE
;
1149 if (Buffer
== NULL
) {
1150 return EFI_INVALID_PARAMETER
;
1153 if (BufferSize
== 0) {
1157 BiosBlockIoDev
= BIOS_BLOCK_IO_FROM_THIS (This
);
1158 ShortLba
= (UINTN
) Lba
;
1160 while (BufferSize
!= 0) {
1162 // Compute I/O location in Sector, Head, Cylinder format
1164 Sector
= (ShortLba
% BiosBlockIoDev
->Bios
.MaxSector
) + 1;
1165 Temp
= ShortLba
/ BiosBlockIoDev
->Bios
.MaxSector
;
1166 Head
= Temp
% (BiosBlockIoDev
->Bios
.MaxHead
+ 1);
1167 Cylinder
= Temp
/ (BiosBlockIoDev
->Bios
.MaxHead
+ 1);
1170 // Limit transfer to this Head & Cylinder
1172 NumberOfBlocks
= BufferSize
/ BlockSize
;
1173 Temp
= BiosBlockIoDev
->Bios
.MaxSector
- Sector
+ 1;
1174 NumberOfBlocks
= NumberOfBlocks
> Temp
? Temp
: NumberOfBlocks
;
1182 Regs
.H
.AL
= (UINT8
) NumberOfBlocks
;
1183 Regs
.H
.DL
= BiosBlockIoDev
->Bios
.Number
;
1185 UpperCylinder
= (Cylinder
& 0x0f00) >> 2;
1187 CheckLba
= Cylinder
* (BiosBlockIoDev
->Bios
.MaxHead
+ 1) + Head
;
1188 CheckLba
= CheckLba
* BiosBlockIoDev
->Bios
.MaxSector
+ Sector
- 1;
1192 "RLD: LBA %x (%x), Sector %x (%x), Head %x (%x), Cyl %x, UCyl %x\n",
1196 BiosBlockIoDev
->Bios
.MaxSector
,
1198 BiosBlockIoDev
->Bios
.MaxHead
,
1202 ASSERT (CheckLba
== ShortLba
);
1204 Regs
.H
.CL
= (UINT8
) ((Sector
& 0x3f) + (UpperCylinder
& 0xff));
1205 Regs
.H
.DH
= (UINT8
) (Head
& 0x3f);
1206 Regs
.H
.CH
= (UINT8
) (Cylinder
& 0xff);
1208 Regs
.X
.BX
= EFI_OFFSET (mEdd11Buffer
);
1209 Regs
.X
.ES
= EFI_SEGMENT (mEdd11Buffer
);
1213 "INT 13h: AX:(02%02x) DX:(%02x%02x) CX:(%02x%02x) BX:(%04x) ES:(%04x)\n",
1215 (UINT8
) (Head
& 0x3f),
1217 (UINT8
) (Cylinder
& 0xff),
1218 (UINT8
) ((Sector
& 0x3f) + (UpperCylinder
& 0xff)),
1219 EFI_OFFSET (mEdd11Buffer
),
1220 EFI_SEGMENT (mEdd11Buffer
))
1223 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
1226 DEBUG_BLKIO
, "BiosReadLegacyDrive: INT 13 02 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev
->Bios
.Number
,
1227 CarryFlag
, Regs
.H
.AH
1231 } while (CarryFlag
!= 0 && Retry
!= 0 && Regs
.H
.AH
!= BIOS_DISK_CHANGED
);
1233 Media
->MediaPresent
= TRUE
;
1234 if (CarryFlag
!= 0) {
1236 // Return Error Status
1238 BiosBlockIoDev
->Bios
.ErrorCode
= Regs
.H
.AH
;
1239 if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_DISK_CHANGED
) {
1241 Bios
= &BiosBlockIoDev
->Bios
;
1242 if (Int13GetDeviceParameters (BiosBlockIoDev
, Bios
) != 0) {
1244 // If the size of the media changed we need to reset the disk geometry
1246 if (Int13Extensions (BiosBlockIoDev
, Bios
) != 0) {
1247 Media
->LastBlock
= (EFI_LBA
) Bios
->Parameters
.PhysicalSectors
- 1;
1248 Media
->BlockSize
= (UINT32
) Bios
->Parameters
.BytesPerSector
;
1251 // Legacy Interfaces
1253 Media
->LastBlock
= (Bios
->MaxHead
+ 1) * Bios
->MaxSector
* (Bios
->MaxCylinder
+ 1) - 1;
1254 Media
->BlockSize
= 512;
1257 Media
->ReadOnly
= FALSE
;
1258 gBS
->HandleProtocol (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
1259 gBS
->ReinstallProtocolInterface (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, BlockIo
, BlockIo
);
1260 return EFI_MEDIA_CHANGED
;
1264 if (Media
->RemovableMedia
) {
1265 Media
->MediaPresent
= FALSE
;
1268 return EFI_DEVICE_ERROR
;
1271 TransferByteSize
= NumberOfBlocks
* BlockSize
;
1272 CopyMem (Buffer
, mEdd11Buffer
, TransferByteSize
);
1274 ShortLba
= ShortLba
+ NumberOfBlocks
;
1275 BufferSize
= BufferSize
- TransferByteSize
;
1276 Buffer
= (VOID
*) ((UINT8
*) Buffer
+ TransferByteSize
);
1283 Write BufferSize bytes from Lba into Buffer.
1285 @param This Indicates a pointer to the calling context.
1286 @param MediaId The media ID that the write request is for.
1287 @param Lba The starting logical block address to be written. The caller is
1288 responsible for writing to only legitimate locations.
1289 @param BufferSize Size of Buffer, must be a multiple of device block size.
1290 @param Buffer A pointer to the source buffer for the data.
1292 @retval EFI_SUCCESS The data was written correctly to the device.
1293 @retval EFI_WRITE_PROTECTED The device can not be written to.
1294 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
1295 @retval EFI_NO_MEDIA There is no media in the device.
1296 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
1297 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
1298 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
1299 or the buffer is not on proper alignment.
1304 BiosWriteLegacyDrive (
1305 IN EFI_BLOCK_IO_PROTOCOL
*This
,
1308 IN UINTN BufferSize
,
1312 EFI_BLOCK_IO_MEDIA
*Media
;
1313 BIOS_BLOCK_IO_DEV
*BiosBlockIoDev
;
1314 EFI_IA32_REGISTER_SET Regs
;
1315 UINTN UpperCylinder
;
1320 UINTN NumberOfBlocks
;
1321 UINTN TransferByteSize
;
1325 BIOS_LEGACY_DRIVE
*Bios
;
1328 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1330 Media
= This
->Media
;
1331 BlockSize
= Media
->BlockSize
;
1333 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
1335 if (MediaId
!= Media
->MediaId
) {
1336 return EFI_MEDIA_CHANGED
;
1339 if (Lba
> Media
->LastBlock
) {
1340 return EFI_INVALID_PARAMETER
;
1343 if ((Lba
+ (BufferSize
/ BlockSize
) - 1) > Media
->LastBlock
) {
1344 return EFI_INVALID_PARAMETER
;
1347 if (BufferSize
% BlockSize
!= 0) {
1348 return EFI_BAD_BUFFER_SIZE
;
1351 if (Buffer
== NULL
) {
1352 return EFI_INVALID_PARAMETER
;
1355 if (BufferSize
== 0) {
1359 BiosBlockIoDev
= BIOS_BLOCK_IO_FROM_THIS (This
);
1360 ShortLba
= (UINTN
) Lba
;
1362 while (BufferSize
!= 0) {
1364 // Compute I/O location in Sector, Head, Cylinder format
1366 Sector
= (ShortLba
% BiosBlockIoDev
->Bios
.MaxSector
) + 1;
1367 Temp
= ShortLba
/ BiosBlockIoDev
->Bios
.MaxSector
;
1368 Head
= Temp
% (BiosBlockIoDev
->Bios
.MaxHead
+ 1);
1369 Cylinder
= Temp
/ (BiosBlockIoDev
->Bios
.MaxHead
+ 1);
1372 // Limit transfer to this Head & Cylinder
1374 NumberOfBlocks
= BufferSize
/ BlockSize
;
1375 Temp
= BiosBlockIoDev
->Bios
.MaxSector
- Sector
+ 1;
1376 NumberOfBlocks
= NumberOfBlocks
> Temp
? Temp
: NumberOfBlocks
;
1384 Regs
.H
.AL
= (UINT8
) NumberOfBlocks
;
1385 Regs
.H
.DL
= BiosBlockIoDev
->Bios
.Number
;
1387 UpperCylinder
= (Cylinder
& 0x0f00) >> 2;
1389 CheckLba
= Cylinder
* (BiosBlockIoDev
->Bios
.MaxHead
+ 1) + Head
;
1390 CheckLba
= CheckLba
* BiosBlockIoDev
->Bios
.MaxSector
+ Sector
- 1;
1394 "RLD: LBA %x (%x), Sector %x (%x), Head %x (%x), Cyl %x, UCyl %x\n",
1398 BiosBlockIoDev
->Bios
.MaxSector
,
1400 BiosBlockIoDev
->Bios
.MaxHead
,
1404 ASSERT (CheckLba
== ShortLba
);
1406 Regs
.H
.CL
= (UINT8
) ((Sector
& 0x3f) + (UpperCylinder
& 0xff));
1407 Regs
.H
.DH
= (UINT8
) (Head
& 0x3f);
1408 Regs
.H
.CH
= (UINT8
) (Cylinder
& 0xff);
1410 Regs
.X
.BX
= EFI_OFFSET (mEdd11Buffer
);
1411 Regs
.X
.ES
= EFI_SEGMENT (mEdd11Buffer
);
1413 TransferByteSize
= NumberOfBlocks
* BlockSize
;
1414 CopyMem (mEdd11Buffer
, Buffer
, TransferByteSize
);
1418 "INT 13h: AX:(03%02x) DX:(%02x%02x) CX:(%02x%02x) BX:(%04x) ES:(%04x)\n",
1420 (UINT8
) (Head
& 0x3f),
1422 (UINT8
) (Cylinder
& 0xff),
1423 (UINT8
) ((Sector
& 0x3f) + (UpperCylinder
& 0xff)),
1424 EFI_OFFSET (mEdd11Buffer
),
1425 EFI_SEGMENT (mEdd11Buffer
))
1428 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
1431 DEBUG_BLKIO
, "BiosWriteLegacyDrive: INT 13 03 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev
->Bios
.Number
,
1432 CarryFlag
, Regs
.H
.AH
1436 } while (CarryFlag
!= 0 && Retry
!= 0 && Regs
.H
.AH
!= BIOS_DISK_CHANGED
);
1438 Media
->MediaPresent
= TRUE
;
1439 if (CarryFlag
!= 0) {
1441 // Return Error Status
1443 BiosBlockIoDev
->Bios
.ErrorCode
= Regs
.H
.AH
;
1444 if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_DISK_CHANGED
) {
1446 Bios
= &BiosBlockIoDev
->Bios
;
1447 if (Int13GetDeviceParameters (BiosBlockIoDev
, Bios
) != 0) {
1448 if (Int13Extensions (BiosBlockIoDev
, Bios
) != 0) {
1449 Media
->LastBlock
= (EFI_LBA
) Bios
->Parameters
.PhysicalSectors
- 1;
1450 Media
->BlockSize
= (UINT32
) Bios
->Parameters
.BytesPerSector
;
1453 // Legacy Interfaces
1455 Media
->LastBlock
= (Bios
->MaxHead
+ 1) * Bios
->MaxSector
* (Bios
->MaxCylinder
+ 1) - 1;
1456 Media
->BlockSize
= 512;
1459 // If the size of the media changed we need to reset the disk geometry
1461 Media
->ReadOnly
= FALSE
;
1462 gBS
->HandleProtocol (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
1463 gBS
->ReinstallProtocolInterface (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, BlockIo
, BlockIo
);
1464 return EFI_MEDIA_CHANGED
;
1466 } else if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_WRITE_PROTECTED
) {
1467 Media
->ReadOnly
= TRUE
;
1468 return EFI_WRITE_PROTECTED
;
1471 if (Media
->RemovableMedia
) {
1472 Media
->MediaPresent
= FALSE
;
1475 return EFI_DEVICE_ERROR
;
1478 Media
->ReadOnly
= FALSE
;
1479 ShortLba
= ShortLba
+ NumberOfBlocks
;
1480 BufferSize
= BufferSize
- TransferByteSize
;
1481 Buffer
= (VOID
*) ((UINT8
*) Buffer
+ TransferByteSize
);