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