2 Routines that use BIOS to support INT 13 devices.
4 Copyright (c) 1999 - 2018, 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;
868 // TransferBuffer has been 4KB alignment. Normalize TransferBuffer to make offset as 0 in seg:offset
869 // format to transfer maximum 127 blocks of data.
870 // Otherwise when offset adding data size exceeds 0xFFFF, if OpROM does not normalize TransferBuffer,
871 // INT13 function 42H will return data boundary error 09H.
873 AddressPacket
->SegOffset
= (UINT32
) LShiftU64 (RShiftU64(TransferBuffer
, 4), 16);
874 AddressPacket
->Lba
= (UINT64
) Lba
;
877 Regs
.H
.DL
= BiosBlockIoDev
->Bios
.Number
;
878 Regs
.X
.SI
= EFI_OFFSET (AddressPacket
);
879 Regs
.X
.DS
= EFI_SEGMENT (AddressPacket
);
881 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
884 DEBUG_BLKIO
, "Edd11BiosReadBlocks: INT 13 42 DL=%02x : CF=%d AH=%02x : LBA 0x%lx Block(s) %0d \n",
885 BiosBlockIoDev
->Bios
.Number
, CarryFlag
, Regs
.H
.AH
, Lba
, NumberOfBlocks
888 Media
->MediaPresent
= TRUE
;
889 if (CarryFlag
!= 0) {
891 // Return Error Status
893 BiosBlockIoDev
->Bios
.ErrorCode
= Regs
.H
.AH
;
894 if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_DISK_CHANGED
) {
896 Bios
= &BiosBlockIoDev
->Bios
;
897 if (Int13GetDeviceParameters (BiosBlockIoDev
, Bios
) != 0) {
898 if (Int13Extensions (BiosBlockIoDev
, Bios
) != 0) {
899 Media
->LastBlock
= (EFI_LBA
) Bios
->Parameters
.PhysicalSectors
- 1;
900 Media
->BlockSize
= (UINT32
) Bios
->Parameters
.BytesPerSector
;
905 Media
->ReadOnly
= FALSE
;
906 gBS
->HandleProtocol (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
907 gBS
->ReinstallProtocolInterface (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, BlockIo
, BlockIo
);
908 return EFI_MEDIA_CHANGED
;
912 if (Media
->RemovableMedia
) {
913 Media
->MediaPresent
= FALSE
;
916 return EFI_DEVICE_ERROR
;
919 TransferByteSize
= NumberOfBlocks
* BlockSize
;
920 CopyMem (Buffer
, (VOID
*) (UINTN
) TransferBuffer
, TransferByteSize
);
921 BufferSize
= BufferSize
- TransferByteSize
;
922 Buffer
= (VOID
*) ((UINT8
*) Buffer
+ TransferByteSize
);
923 Lba
+= NumberOfBlocks
;
930 Write BufferSize bytes from Lba into Buffer.
932 @param This Indicates a pointer to the calling context.
933 @param MediaId The media ID that the write request is for.
934 @param Lba The starting logical block address to be written. The caller is
935 responsible for writing to only legitimate locations.
936 @param BufferSize Size of Buffer, must be a multiple of device block size.
937 @param Buffer A pointer to the source buffer for the data.
939 @retval EFI_SUCCESS The data was written correctly to the device.
940 @retval EFI_WRITE_PROTECTED The device can not be written to.
941 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
942 @retval EFI_NO_MEDIA There is no media in the device.
943 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
944 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
945 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
946 or the buffer is not on proper alignment.
951 Edd11BiosWriteBlocks (
952 IN EFI_BLOCK_IO_PROTOCOL
*This
,
959 EFI_BLOCK_IO_MEDIA
*Media
;
960 BIOS_BLOCK_IO_DEV
*BiosBlockIoDev
;
961 EDD_DEVICE_ADDRESS_PACKET
*AddressPacket
;
963 // I exist only for readability
965 EFI_IA32_REGISTER_SET Regs
;
966 UINT64 TransferBuffer
;
967 UINTN NumberOfBlocks
;
968 UINTN TransferByteSize
;
970 BIOS_LEGACY_DRIVE
*Bios
;
972 UINTN MaxTransferBlocks
;
973 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
976 BlockSize
= Media
->BlockSize
;
978 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
980 if (MediaId
!= Media
->MediaId
) {
981 return EFI_MEDIA_CHANGED
;
984 if (Lba
> Media
->LastBlock
) {
985 return EFI_INVALID_PARAMETER
;
988 if ((Lba
+ (BufferSize
/ BlockSize
) - 1) > Media
->LastBlock
) {
989 return EFI_INVALID_PARAMETER
;
992 if (BufferSize
% BlockSize
!= 0) {
993 return EFI_BAD_BUFFER_SIZE
;
996 if (Buffer
== NULL
) {
997 return EFI_INVALID_PARAMETER
;
1000 if (BufferSize
== 0) {
1004 BiosBlockIoDev
= BIOS_BLOCK_IO_FROM_THIS (This
);
1005 AddressPacket
= mEddBufferUnder1Mb
;
1007 MaxTransferBlocks
= MAX_EDD11_XFER
/ BlockSize
;
1009 TransferBuffer
= (UINT64
)(UINTN
) mEdd11Buffer
;
1010 for (; BufferSize
> 0;) {
1011 NumberOfBlocks
= BufferSize
/ BlockSize
;
1012 NumberOfBlocks
= NumberOfBlocks
> MaxTransferBlocks
? MaxTransferBlocks
: NumberOfBlocks
;
1014 // Max transfer MaxTransferBlocks
1016 AddressPacket
->PacketSizeInBytes
= (UINT8
) sizeof (EDD_DEVICE_ADDRESS_PACKET
);
1017 AddressPacket
->Zero
= 0;
1018 AddressPacket
->NumberOfBlocks
= (UINT8
) NumberOfBlocks
;
1019 AddressPacket
->Zero2
= 0;
1021 // TransferBuffer has been 4KB alignment. Normalize TransferBuffer to make offset as 0 in seg:offset
1022 // format to transfer maximum 127 blocks of data.
1023 // Otherwise when offset adding data size exceeds 0xFFFF, if OpROM does not normalize TransferBuffer,
1024 // INT13 function 42H will return data boundary error 09H.
1026 AddressPacket
->SegOffset
= (UINT32
) LShiftU64 (RShiftU64(TransferBuffer
, 4), 16);
1027 AddressPacket
->Lba
= (UINT64
) Lba
;
1032 // Write Verify disable
1034 Regs
.H
.DL
= BiosBlockIoDev
->Bios
.Number
;
1035 Regs
.X
.SI
= EFI_OFFSET (AddressPacket
);
1036 Regs
.X
.DS
= EFI_SEGMENT (AddressPacket
);
1038 TransferByteSize
= NumberOfBlocks
* BlockSize
;
1039 CopyMem ((VOID
*) (UINTN
) TransferBuffer
, Buffer
, TransferByteSize
);
1041 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
1044 DEBUG_BLKIO
, "Edd11BiosWriteBlocks: INT 13 43 DL=%02x : CF=%d AH=%02x\n: LBA 0x%lx Block(s) %0d \n",
1045 BiosBlockIoDev
->Bios
.Number
, CarryFlag
, Regs
.H
.AH
, Lba
, NumberOfBlocks
1048 Media
->MediaPresent
= TRUE
;
1049 if (CarryFlag
!= 0) {
1051 // Return Error Status
1053 BiosBlockIoDev
->Bios
.ErrorCode
= Regs
.H
.AH
;
1054 if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_DISK_CHANGED
) {
1056 Bios
= &BiosBlockIoDev
->Bios
;
1057 if (Int13GetDeviceParameters (BiosBlockIoDev
, Bios
) != 0) {
1058 if (Int13Extensions (BiosBlockIoDev
, Bios
) != 0) {
1059 Media
->LastBlock
= (EFI_LBA
) Bios
->Parameters
.PhysicalSectors
- 1;
1060 Media
->BlockSize
= (UINT32
) Bios
->Parameters
.BytesPerSector
;
1065 Media
->ReadOnly
= FALSE
;
1066 gBS
->HandleProtocol (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
1067 gBS
->ReinstallProtocolInterface (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, BlockIo
, BlockIo
);
1068 return EFI_MEDIA_CHANGED
;
1070 } else if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_WRITE_PROTECTED
) {
1071 Media
->ReadOnly
= TRUE
;
1072 return EFI_WRITE_PROTECTED
;
1075 if (Media
->RemovableMedia
) {
1076 Media
->MediaPresent
= FALSE
;
1079 return EFI_DEVICE_ERROR
;
1082 Media
->ReadOnly
= FALSE
;
1083 BufferSize
= BufferSize
- TransferByteSize
;
1084 Buffer
= (VOID
*) ((UINT8
*) Buffer
+ TransferByteSize
);
1085 Lba
+= NumberOfBlocks
;
1092 Read BufferSize bytes from Lba into Buffer.
1094 @param This Indicates a pointer to the calling context.
1095 @param MediaId Id of the media, changes every time the media is replaced.
1096 @param Lba The starting Logical Block Address to read from
1097 @param BufferSize Size of Buffer, must be a multiple of device block size.
1098 @param Buffer A pointer to the destination buffer for the data. The caller is
1099 responsible for either having implicit or explicit ownership of the buffer.
1101 @retval EFI_SUCCESS The data was read correctly from the device.
1102 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
1103 @retval EFI_NO_MEDIA There is no media in the device.
1104 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
1105 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
1106 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
1107 or the buffer is not on proper alignment.
1112 BiosReadLegacyDrive (
1113 IN EFI_BLOCK_IO_PROTOCOL
*This
,
1116 IN UINTN BufferSize
,
1120 EFI_BLOCK_IO_MEDIA
*Media
;
1121 BIOS_BLOCK_IO_DEV
*BiosBlockIoDev
;
1122 EFI_IA32_REGISTER_SET Regs
;
1123 UINTN UpperCylinder
;
1128 UINTN NumberOfBlocks
;
1129 UINTN TransferByteSize
;
1133 BIOS_LEGACY_DRIVE
*Bios
;
1136 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1138 Media
= This
->Media
;
1139 BlockSize
= Media
->BlockSize
;
1141 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
1143 if (MediaId
!= Media
->MediaId
) {
1144 return EFI_MEDIA_CHANGED
;
1147 if (Lba
> Media
->LastBlock
) {
1148 return EFI_INVALID_PARAMETER
;
1151 if ((Lba
+ (BufferSize
/ BlockSize
) - 1) > Media
->LastBlock
) {
1152 return EFI_INVALID_PARAMETER
;
1155 if (BufferSize
% BlockSize
!= 0) {
1156 return EFI_BAD_BUFFER_SIZE
;
1159 if (Buffer
== NULL
) {
1160 return EFI_INVALID_PARAMETER
;
1163 if (BufferSize
== 0) {
1167 BiosBlockIoDev
= BIOS_BLOCK_IO_FROM_THIS (This
);
1168 ShortLba
= (UINTN
) Lba
;
1170 while (BufferSize
!= 0) {
1172 // Compute I/O location in Sector, Head, Cylinder format
1174 Sector
= (ShortLba
% BiosBlockIoDev
->Bios
.MaxSector
) + 1;
1175 Temp
= ShortLba
/ BiosBlockIoDev
->Bios
.MaxSector
;
1176 Head
= Temp
% (BiosBlockIoDev
->Bios
.MaxHead
+ 1);
1177 Cylinder
= Temp
/ (BiosBlockIoDev
->Bios
.MaxHead
+ 1);
1180 // Limit transfer to this Head & Cylinder
1182 NumberOfBlocks
= BufferSize
/ BlockSize
;
1183 Temp
= BiosBlockIoDev
->Bios
.MaxSector
- Sector
+ 1;
1184 NumberOfBlocks
= NumberOfBlocks
> Temp
? Temp
: NumberOfBlocks
;
1192 Regs
.H
.AL
= (UINT8
) NumberOfBlocks
;
1193 Regs
.H
.DL
= BiosBlockIoDev
->Bios
.Number
;
1195 UpperCylinder
= (Cylinder
& 0x0f00) >> 2;
1197 CheckLba
= Cylinder
* (BiosBlockIoDev
->Bios
.MaxHead
+ 1) + Head
;
1198 CheckLba
= CheckLba
* BiosBlockIoDev
->Bios
.MaxSector
+ Sector
- 1;
1202 "RLD: LBA %x (%x), Sector %x (%x), Head %x (%x), Cyl %x, UCyl %x\n",
1206 BiosBlockIoDev
->Bios
.MaxSector
,
1208 BiosBlockIoDev
->Bios
.MaxHead
,
1212 ASSERT (CheckLba
== ShortLba
);
1214 Regs
.H
.CL
= (UINT8
) ((Sector
& 0x3f) + (UpperCylinder
& 0xff));
1215 Regs
.H
.DH
= (UINT8
) (Head
& 0x3f);
1216 Regs
.H
.CH
= (UINT8
) (Cylinder
& 0xff);
1218 Regs
.X
.BX
= EFI_OFFSET (mEdd11Buffer
);
1219 Regs
.X
.ES
= EFI_SEGMENT (mEdd11Buffer
);
1223 "INT 13h: AX:(02%02x) DX:(%02x%02x) CX:(%02x%02x) BX:(%04x) ES:(%04x)\n",
1225 (UINT8
) (Head
& 0x3f),
1227 (UINT8
) (Cylinder
& 0xff),
1228 (UINT8
) ((Sector
& 0x3f) + (UpperCylinder
& 0xff)),
1229 EFI_OFFSET (mEdd11Buffer
),
1230 EFI_SEGMENT (mEdd11Buffer
))
1233 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
1236 DEBUG_BLKIO
, "BiosReadLegacyDrive: INT 13 02 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev
->Bios
.Number
,
1237 CarryFlag
, Regs
.H
.AH
1241 } while (CarryFlag
!= 0 && Retry
!= 0 && Regs
.H
.AH
!= BIOS_DISK_CHANGED
);
1243 Media
->MediaPresent
= TRUE
;
1244 if (CarryFlag
!= 0) {
1246 // Return Error Status
1248 BiosBlockIoDev
->Bios
.ErrorCode
= Regs
.H
.AH
;
1249 if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_DISK_CHANGED
) {
1251 Bios
= &BiosBlockIoDev
->Bios
;
1252 if (Int13GetDeviceParameters (BiosBlockIoDev
, Bios
) != 0) {
1254 // If the size of the media changed we need to reset the disk geometry
1256 if (Int13Extensions (BiosBlockIoDev
, Bios
) != 0) {
1257 Media
->LastBlock
= (EFI_LBA
) Bios
->Parameters
.PhysicalSectors
- 1;
1258 Media
->BlockSize
= (UINT32
) Bios
->Parameters
.BytesPerSector
;
1261 // Legacy Interfaces
1263 Media
->LastBlock
= (Bios
->MaxHead
+ 1) * Bios
->MaxSector
* (Bios
->MaxCylinder
+ 1) - 1;
1264 Media
->BlockSize
= 512;
1267 Media
->ReadOnly
= FALSE
;
1268 gBS
->HandleProtocol (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
1269 gBS
->ReinstallProtocolInterface (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, BlockIo
, BlockIo
);
1270 return EFI_MEDIA_CHANGED
;
1274 if (Media
->RemovableMedia
) {
1275 Media
->MediaPresent
= FALSE
;
1278 return EFI_DEVICE_ERROR
;
1281 TransferByteSize
= NumberOfBlocks
* BlockSize
;
1282 CopyMem (Buffer
, mEdd11Buffer
, TransferByteSize
);
1284 ShortLba
= ShortLba
+ NumberOfBlocks
;
1285 BufferSize
= BufferSize
- TransferByteSize
;
1286 Buffer
= (VOID
*) ((UINT8
*) Buffer
+ TransferByteSize
);
1293 Write BufferSize bytes from Lba into Buffer.
1295 @param This Indicates a pointer to the calling context.
1296 @param MediaId The media ID that the write request is for.
1297 @param Lba The starting logical block address to be written. The caller is
1298 responsible for writing to only legitimate locations.
1299 @param BufferSize Size of Buffer, must be a multiple of device block size.
1300 @param Buffer A pointer to the source buffer for the data.
1302 @retval EFI_SUCCESS The data was written correctly to the device.
1303 @retval EFI_WRITE_PROTECTED The device can not be written to.
1304 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
1305 @retval EFI_NO_MEDIA There is no media in the device.
1306 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
1307 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
1308 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
1309 or the buffer is not on proper alignment.
1314 BiosWriteLegacyDrive (
1315 IN EFI_BLOCK_IO_PROTOCOL
*This
,
1318 IN UINTN BufferSize
,
1322 EFI_BLOCK_IO_MEDIA
*Media
;
1323 BIOS_BLOCK_IO_DEV
*BiosBlockIoDev
;
1324 EFI_IA32_REGISTER_SET Regs
;
1325 UINTN UpperCylinder
;
1330 UINTN NumberOfBlocks
;
1331 UINTN TransferByteSize
;
1335 BIOS_LEGACY_DRIVE
*Bios
;
1338 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
1340 Media
= This
->Media
;
1341 BlockSize
= Media
->BlockSize
;
1343 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
1345 if (MediaId
!= Media
->MediaId
) {
1346 return EFI_MEDIA_CHANGED
;
1349 if (Lba
> Media
->LastBlock
) {
1350 return EFI_INVALID_PARAMETER
;
1353 if ((Lba
+ (BufferSize
/ BlockSize
) - 1) > Media
->LastBlock
) {
1354 return EFI_INVALID_PARAMETER
;
1357 if (BufferSize
% BlockSize
!= 0) {
1358 return EFI_BAD_BUFFER_SIZE
;
1361 if (Buffer
== NULL
) {
1362 return EFI_INVALID_PARAMETER
;
1365 if (BufferSize
== 0) {
1369 BiosBlockIoDev
= BIOS_BLOCK_IO_FROM_THIS (This
);
1370 ShortLba
= (UINTN
) Lba
;
1372 while (BufferSize
!= 0) {
1374 // Compute I/O location in Sector, Head, Cylinder format
1376 Sector
= (ShortLba
% BiosBlockIoDev
->Bios
.MaxSector
) + 1;
1377 Temp
= ShortLba
/ BiosBlockIoDev
->Bios
.MaxSector
;
1378 Head
= Temp
% (BiosBlockIoDev
->Bios
.MaxHead
+ 1);
1379 Cylinder
= Temp
/ (BiosBlockIoDev
->Bios
.MaxHead
+ 1);
1382 // Limit transfer to this Head & Cylinder
1384 NumberOfBlocks
= BufferSize
/ BlockSize
;
1385 Temp
= BiosBlockIoDev
->Bios
.MaxSector
- Sector
+ 1;
1386 NumberOfBlocks
= NumberOfBlocks
> Temp
? Temp
: NumberOfBlocks
;
1394 Regs
.H
.AL
= (UINT8
) NumberOfBlocks
;
1395 Regs
.H
.DL
= BiosBlockIoDev
->Bios
.Number
;
1397 UpperCylinder
= (Cylinder
& 0x0f00) >> 2;
1399 CheckLba
= Cylinder
* (BiosBlockIoDev
->Bios
.MaxHead
+ 1) + Head
;
1400 CheckLba
= CheckLba
* BiosBlockIoDev
->Bios
.MaxSector
+ Sector
- 1;
1404 "RLD: LBA %x (%x), Sector %x (%x), Head %x (%x), Cyl %x, UCyl %x\n",
1408 BiosBlockIoDev
->Bios
.MaxSector
,
1410 BiosBlockIoDev
->Bios
.MaxHead
,
1414 ASSERT (CheckLba
== ShortLba
);
1416 Regs
.H
.CL
= (UINT8
) ((Sector
& 0x3f) + (UpperCylinder
& 0xff));
1417 Regs
.H
.DH
= (UINT8
) (Head
& 0x3f);
1418 Regs
.H
.CH
= (UINT8
) (Cylinder
& 0xff);
1420 Regs
.X
.BX
= EFI_OFFSET (mEdd11Buffer
);
1421 Regs
.X
.ES
= EFI_SEGMENT (mEdd11Buffer
);
1423 TransferByteSize
= NumberOfBlocks
* BlockSize
;
1424 CopyMem (mEdd11Buffer
, Buffer
, TransferByteSize
);
1428 "INT 13h: AX:(03%02x) DX:(%02x%02x) CX:(%02x%02x) BX:(%04x) ES:(%04x)\n",
1430 (UINT8
) (Head
& 0x3f),
1432 (UINT8
) (Cylinder
& 0xff),
1433 (UINT8
) ((Sector
& 0x3f) + (UpperCylinder
& 0xff)),
1434 EFI_OFFSET (mEdd11Buffer
),
1435 EFI_SEGMENT (mEdd11Buffer
))
1438 CarryFlag
= BiosBlockIoDev
->LegacyBios
->Int86 (BiosBlockIoDev
->LegacyBios
, 0x13, &Regs
);
1441 DEBUG_BLKIO
, "BiosWriteLegacyDrive: INT 13 03 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev
->Bios
.Number
,
1442 CarryFlag
, Regs
.H
.AH
1446 } while (CarryFlag
!= 0 && Retry
!= 0 && Regs
.H
.AH
!= BIOS_DISK_CHANGED
);
1448 Media
->MediaPresent
= TRUE
;
1449 if (CarryFlag
!= 0) {
1451 // Return Error Status
1453 BiosBlockIoDev
->Bios
.ErrorCode
= Regs
.H
.AH
;
1454 if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_DISK_CHANGED
) {
1456 Bios
= &BiosBlockIoDev
->Bios
;
1457 if (Int13GetDeviceParameters (BiosBlockIoDev
, Bios
) != 0) {
1458 if (Int13Extensions (BiosBlockIoDev
, Bios
) != 0) {
1459 Media
->LastBlock
= (EFI_LBA
) Bios
->Parameters
.PhysicalSectors
- 1;
1460 Media
->BlockSize
= (UINT32
) Bios
->Parameters
.BytesPerSector
;
1463 // Legacy Interfaces
1465 Media
->LastBlock
= (Bios
->MaxHead
+ 1) * Bios
->MaxSector
* (Bios
->MaxCylinder
+ 1) - 1;
1466 Media
->BlockSize
= 512;
1469 // If the size of the media changed we need to reset the disk geometry
1471 Media
->ReadOnly
= FALSE
;
1472 gBS
->HandleProtocol (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, (VOID
**) &BlockIo
);
1473 gBS
->ReinstallProtocolInterface (BiosBlockIoDev
->Handle
, &gEfiBlockIoProtocolGuid
, BlockIo
, BlockIo
);
1474 return EFI_MEDIA_CHANGED
;
1476 } else if (BiosBlockIoDev
->Bios
.ErrorCode
== BIOS_WRITE_PROTECTED
) {
1477 Media
->ReadOnly
= TRUE
;
1478 return EFI_WRITE_PROTECTED
;
1481 if (Media
->RemovableMedia
) {
1482 Media
->MediaPresent
= FALSE
;
1485 return EFI_DEVICE_ERROR
;
1488 Media
->ReadOnly
= FALSE
;
1489 ShortLba
= ShortLba
+ NumberOfBlocks
;
1490 BufferSize
= BufferSize
- TransferByteSize
;
1491 Buffer
= (VOID
*) ((UINT8
*) Buffer
+ TransferByteSize
);