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