]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosInt13.c
IntelFrameworkModulePkg: Add Compatibility Support Module (CSM) drivers
[mirror_edk2.git] / IntelFrameworkModulePkg / Csm / BiosThunk / BlockIoDxe / BiosInt13.c
1 /** @file
2 Routines that use BIOS to support INT 13 devices.
3
4 Copyright (c) 1999 - 2010, 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
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
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
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
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
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
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
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
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
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 AddressPacket->SegOffset = EFI_SEGMENT (TransferBuffer) << 16;
868 AddressPacket->SegOffset |= EFI_OFFSET (TransferBuffer);
869 AddressPacket->Lba = (UINT64) Lba;
870
871 Regs.H.AH = 0x42;
872 Regs.H.DL = BiosBlockIoDev->Bios.Number;
873 Regs.X.SI = EFI_OFFSET (AddressPacket);
874 Regs.X.DS = EFI_SEGMENT (AddressPacket);
875
876 CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
877 DEBUG (
878 (
879 DEBUG_BLKIO, "Edd11BiosReadBlocks: INT 13 42 DL=%02x : CF=%d AH=%02x : LBA 0x%lx Block(s) %0d \n",
880 BiosBlockIoDev->Bios.Number, CarryFlag, Regs.H.AH, Lba, NumberOfBlocks
881 )
882 );
883 Media->MediaPresent = TRUE;
884 if (CarryFlag != 0) {
885 //
886 // Return Error Status
887 //
888 BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
889 if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
890 Media->MediaId++;
891 Bios = &BiosBlockIoDev->Bios;
892 if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
893 if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
894 Media->LastBlock = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
895 Media->BlockSize = (UINT32) Bios->Parameters.BytesPerSector;
896 } else {
897 ASSERT (FALSE);
898 }
899
900 Media->ReadOnly = FALSE;
901 gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
902 gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
903 return EFI_MEDIA_CHANGED;
904 }
905 }
906
907 if (Media->RemovableMedia) {
908 Media->MediaPresent = FALSE;
909 }
910
911 return EFI_DEVICE_ERROR;
912 }
913
914 TransferByteSize = NumberOfBlocks * BlockSize;
915 CopyMem (Buffer, (VOID *) (UINTN) TransferBuffer, TransferByteSize);
916 BufferSize = BufferSize - TransferByteSize;
917 Buffer = (VOID *) ((UINT8 *) Buffer + TransferByteSize);
918 Lba += NumberOfBlocks;
919 }
920
921 return EFI_SUCCESS;
922 }
923
924 /**
925 Write BufferSize bytes from Lba into Buffer.
926
927 @param This Indicates a pointer to the calling context.
928 @param MediaId The media ID that the write request is for.
929 @param Lba The starting logical block address to be written. The caller is
930 responsible for writing to only legitimate locations.
931 @param BufferSize Size of Buffer, must be a multiple of device block size.
932 @param Buffer A pointer to the source buffer for the data.
933
934 @retval EFI_SUCCESS The data was written correctly to the device.
935 @retval EFI_WRITE_PROTECTED The device can not be written to.
936 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
937 @retval EFI_NO_MEDIA There is no media in the device.
938 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
939 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
940 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
941 or the buffer is not on proper alignment.
942
943 **/
944 EFI_STATUS
945 EFIAPI
946 Edd11BiosWriteBlocks (
947 IN EFI_BLOCK_IO_PROTOCOL *This,
948 IN UINT32 MediaId,
949 IN EFI_LBA Lba,
950 IN UINTN BufferSize,
951 OUT VOID *Buffer
952 )
953 {
954 EFI_BLOCK_IO_MEDIA *Media;
955 BIOS_BLOCK_IO_DEV *BiosBlockIoDev;
956 EDD_DEVICE_ADDRESS_PACKET *AddressPacket;
957 //
958 // I exist only for readability
959 //
960 EFI_IA32_REGISTER_SET Regs;
961 UINT64 TransferBuffer;
962 UINTN NumberOfBlocks;
963 UINTN TransferByteSize;
964 UINTN BlockSize;
965 BIOS_LEGACY_DRIVE *Bios;
966 UINTN CarryFlag;
967 UINTN MaxTransferBlocks;
968 EFI_BLOCK_IO_PROTOCOL *BlockIo;
969
970 Media = This->Media;
971 BlockSize = Media->BlockSize;
972
973 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
974
975 if (MediaId != Media->MediaId) {
976 return EFI_MEDIA_CHANGED;
977 }
978
979 if (Lba > Media->LastBlock) {
980 return EFI_INVALID_PARAMETER;
981 }
982
983 if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
984 return EFI_INVALID_PARAMETER;
985 }
986
987 if (BufferSize % BlockSize != 0) {
988 return EFI_BAD_BUFFER_SIZE;
989 }
990
991 if (Buffer == NULL) {
992 return EFI_INVALID_PARAMETER;
993 }
994
995 if (BufferSize == 0) {
996 return EFI_SUCCESS;
997 }
998
999 BiosBlockIoDev = BIOS_BLOCK_IO_FROM_THIS (This);
1000 AddressPacket = mEddBufferUnder1Mb;
1001
1002 MaxTransferBlocks = MAX_EDD11_XFER / BlockSize;
1003
1004 TransferBuffer = (UINT64)(UINTN) mEdd11Buffer;
1005 for (; BufferSize > 0;) {
1006 NumberOfBlocks = BufferSize / BlockSize;
1007 NumberOfBlocks = NumberOfBlocks > MaxTransferBlocks ? MaxTransferBlocks : NumberOfBlocks;
1008 //
1009 // Max transfer MaxTransferBlocks
1010 //
1011 AddressPacket->PacketSizeInBytes = (UINT8) sizeof (EDD_DEVICE_ADDRESS_PACKET);
1012 AddressPacket->Zero = 0;
1013 AddressPacket->NumberOfBlocks = (UINT8) NumberOfBlocks;
1014 AddressPacket->Zero2 = 0;
1015 AddressPacket->SegOffset = EFI_SEGMENT (TransferBuffer) << 16;
1016 AddressPacket->SegOffset |= EFI_OFFSET (TransferBuffer);
1017 AddressPacket->Lba = (UINT64) Lba;
1018
1019 Regs.H.AH = 0x43;
1020 Regs.H.AL = 0x00;
1021 //
1022 // Write Verify disable
1023 //
1024 Regs.H.DL = BiosBlockIoDev->Bios.Number;
1025 Regs.X.SI = EFI_OFFSET (AddressPacket);
1026 Regs.X.DS = EFI_SEGMENT (AddressPacket);
1027
1028 TransferByteSize = NumberOfBlocks * BlockSize;
1029 CopyMem ((VOID *) (UINTN) TransferBuffer, Buffer, TransferByteSize);
1030
1031 CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
1032 DEBUG (
1033 (
1034 DEBUG_BLKIO, "Edd11BiosWriteBlocks: INT 13 43 DL=%02x : CF=%d AH=%02x\n: LBA 0x%lx Block(s) %0d \n",
1035 BiosBlockIoDev->Bios.Number, CarryFlag, Regs.H.AH, Lba, NumberOfBlocks
1036 )
1037 );
1038 Media->MediaPresent = TRUE;
1039 if (CarryFlag != 0) {
1040 //
1041 // Return Error Status
1042 //
1043 BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
1044 if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
1045 Media->MediaId++;
1046 Bios = &BiosBlockIoDev->Bios;
1047 if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
1048 if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
1049 Media->LastBlock = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
1050 Media->BlockSize = (UINT32) Bios->Parameters.BytesPerSector;
1051 } else {
1052 ASSERT (FALSE);
1053 }
1054
1055 Media->ReadOnly = FALSE;
1056 gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
1057 gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
1058 return EFI_MEDIA_CHANGED;
1059 }
1060 } else if (BiosBlockIoDev->Bios.ErrorCode == BIOS_WRITE_PROTECTED) {
1061 Media->ReadOnly = TRUE;
1062 return EFI_WRITE_PROTECTED;
1063 }
1064
1065 if (Media->RemovableMedia) {
1066 Media->MediaPresent = FALSE;
1067 }
1068
1069 return EFI_DEVICE_ERROR;
1070 }
1071
1072 Media->ReadOnly = FALSE;
1073 BufferSize = BufferSize - TransferByteSize;
1074 Buffer = (VOID *) ((UINT8 *) Buffer + TransferByteSize);
1075 Lba += NumberOfBlocks;
1076 }
1077
1078 return EFI_SUCCESS;
1079 }
1080
1081 /**
1082 Read BufferSize bytes from Lba into Buffer.
1083
1084 @param This Indicates a pointer to the calling context.
1085 @param MediaId Id of the media, changes every time the media is replaced.
1086 @param Lba The starting Logical Block Address to read from
1087 @param BufferSize Size of Buffer, must be a multiple of device block size.
1088 @param Buffer A pointer to the destination buffer for the data. The caller is
1089 responsible for either having implicit or explicit ownership of the buffer.
1090
1091 @retval EFI_SUCCESS The data was read correctly from the device.
1092 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
1093 @retval EFI_NO_MEDIA There is no media in the device.
1094 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
1095 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
1096 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
1097 or the buffer is not on proper alignment.
1098
1099 **/
1100 EFI_STATUS
1101 EFIAPI
1102 BiosReadLegacyDrive (
1103 IN EFI_BLOCK_IO_PROTOCOL *This,
1104 IN UINT32 MediaId,
1105 IN EFI_LBA Lba,
1106 IN UINTN BufferSize,
1107 OUT VOID *Buffer
1108 )
1109 {
1110 EFI_BLOCK_IO_MEDIA *Media;
1111 BIOS_BLOCK_IO_DEV *BiosBlockIoDev;
1112 EFI_IA32_REGISTER_SET Regs;
1113 UINTN UpperCylinder;
1114 UINTN Temp;
1115 UINTN Cylinder;
1116 UINTN Head;
1117 UINTN Sector;
1118 UINTN NumberOfBlocks;
1119 UINTN TransferByteSize;
1120 UINTN ShortLba;
1121 UINTN CheckLba;
1122 UINTN BlockSize;
1123 BIOS_LEGACY_DRIVE *Bios;
1124 UINTN CarryFlag;
1125 UINTN Retry;
1126 EFI_BLOCK_IO_PROTOCOL *BlockIo;
1127
1128 Media = This->Media;
1129 BlockSize = Media->BlockSize;
1130
1131 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
1132
1133 if (MediaId != Media->MediaId) {
1134 return EFI_MEDIA_CHANGED;
1135 }
1136
1137 if (Lba > Media->LastBlock) {
1138 return EFI_INVALID_PARAMETER;
1139 }
1140
1141 if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
1142 return EFI_INVALID_PARAMETER;
1143 }
1144
1145 if (BufferSize % BlockSize != 0) {
1146 return EFI_BAD_BUFFER_SIZE;
1147 }
1148
1149 if (Buffer == NULL) {
1150 return EFI_INVALID_PARAMETER;
1151 }
1152
1153 if (BufferSize == 0) {
1154 return EFI_SUCCESS;
1155 }
1156
1157 BiosBlockIoDev = BIOS_BLOCK_IO_FROM_THIS (This);
1158 ShortLba = (UINTN) Lba;
1159
1160 while (BufferSize != 0) {
1161 //
1162 // Compute I/O location in Sector, Head, Cylinder format
1163 //
1164 Sector = (ShortLba % BiosBlockIoDev->Bios.MaxSector) + 1;
1165 Temp = ShortLba / BiosBlockIoDev->Bios.MaxSector;
1166 Head = Temp % (BiosBlockIoDev->Bios.MaxHead + 1);
1167 Cylinder = Temp / (BiosBlockIoDev->Bios.MaxHead + 1);
1168
1169 //
1170 // Limit transfer to this Head & Cylinder
1171 //
1172 NumberOfBlocks = BufferSize / BlockSize;
1173 Temp = BiosBlockIoDev->Bios.MaxSector - Sector + 1;
1174 NumberOfBlocks = NumberOfBlocks > Temp ? Temp : NumberOfBlocks;
1175
1176 Retry = 3;
1177 do {
1178 //
1179 // Perform the IO
1180 //
1181 Regs.H.AH = 2;
1182 Regs.H.AL = (UINT8) NumberOfBlocks;
1183 Regs.H.DL = BiosBlockIoDev->Bios.Number;
1184
1185 UpperCylinder = (Cylinder & 0x0f00) >> 2;
1186
1187 CheckLba = Cylinder * (BiosBlockIoDev->Bios.MaxHead + 1) + Head;
1188 CheckLba = CheckLba * BiosBlockIoDev->Bios.MaxSector + Sector - 1;
1189
1190 DEBUG (
1191 (DEBUG_BLKIO,
1192 "RLD: LBA %x (%x), Sector %x (%x), Head %x (%x), Cyl %x, UCyl %x\n",
1193 ShortLba,
1194 CheckLba,
1195 Sector,
1196 BiosBlockIoDev->Bios.MaxSector,
1197 Head,
1198 BiosBlockIoDev->Bios.MaxHead,
1199 Cylinder,
1200 UpperCylinder)
1201 );
1202 ASSERT (CheckLba == ShortLba);
1203
1204 Regs.H.CL = (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff));
1205 Regs.H.DH = (UINT8) (Head & 0x3f);
1206 Regs.H.CH = (UINT8) (Cylinder & 0xff);
1207
1208 Regs.X.BX = EFI_OFFSET (mEdd11Buffer);
1209 Regs.X.ES = EFI_SEGMENT (mEdd11Buffer);
1210
1211 DEBUG (
1212 (DEBUG_BLKIO,
1213 "INT 13h: AX:(02%02x) DX:(%02x%02x) CX:(%02x%02x) BX:(%04x) ES:(%04x)\n",
1214 Regs.H.AL,
1215 (UINT8) (Head & 0x3f),
1216 Regs.H.DL,
1217 (UINT8) (Cylinder & 0xff),
1218 (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff)),
1219 EFI_OFFSET (mEdd11Buffer),
1220 EFI_SEGMENT (mEdd11Buffer))
1221 );
1222
1223 CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
1224 DEBUG (
1225 (
1226 DEBUG_BLKIO, "BiosReadLegacyDrive: INT 13 02 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number,
1227 CarryFlag, Regs.H.AH
1228 )
1229 );
1230 Retry--;
1231 } while (CarryFlag != 0 && Retry != 0 && Regs.H.AH != BIOS_DISK_CHANGED);
1232
1233 Media->MediaPresent = TRUE;
1234 if (CarryFlag != 0) {
1235 //
1236 // Return Error Status
1237 //
1238 BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
1239 if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
1240 Media->MediaId++;
1241 Bios = &BiosBlockIoDev->Bios;
1242 if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
1243 //
1244 // If the size of the media changed we need to reset the disk geometry
1245 //
1246 if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
1247 Media->LastBlock = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
1248 Media->BlockSize = (UINT32) Bios->Parameters.BytesPerSector;
1249 } else {
1250 //
1251 // Legacy Interfaces
1252 //
1253 Media->LastBlock = (Bios->MaxHead + 1) * Bios->MaxSector * (Bios->MaxCylinder + 1) - 1;
1254 Media->BlockSize = 512;
1255 }
1256
1257 Media->ReadOnly = FALSE;
1258 gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
1259 gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
1260 return EFI_MEDIA_CHANGED;
1261 }
1262 }
1263
1264 if (Media->RemovableMedia) {
1265 Media->MediaPresent = FALSE;
1266 }
1267
1268 return EFI_DEVICE_ERROR;
1269 }
1270
1271 TransferByteSize = NumberOfBlocks * BlockSize;
1272 CopyMem (Buffer, mEdd11Buffer, TransferByteSize);
1273
1274 ShortLba = ShortLba + NumberOfBlocks;
1275 BufferSize = BufferSize - TransferByteSize;
1276 Buffer = (VOID *) ((UINT8 *) Buffer + TransferByteSize);
1277 }
1278
1279 return EFI_SUCCESS;
1280 }
1281
1282 /**
1283 Write BufferSize bytes from Lba into Buffer.
1284
1285 @param This Indicates a pointer to the calling context.
1286 @param MediaId The media ID that the write request is for.
1287 @param Lba The starting logical block address to be written. The caller is
1288 responsible for writing to only legitimate locations.
1289 @param BufferSize Size of Buffer, must be a multiple of device block size.
1290 @param Buffer A pointer to the source buffer for the data.
1291
1292 @retval EFI_SUCCESS The data was written correctly to the device.
1293 @retval EFI_WRITE_PROTECTED The device can not be written to.
1294 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
1295 @retval EFI_NO_MEDIA There is no media in the device.
1296 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
1297 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
1298 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
1299 or the buffer is not on proper alignment.
1300
1301 **/
1302 EFI_STATUS
1303 EFIAPI
1304 BiosWriteLegacyDrive (
1305 IN EFI_BLOCK_IO_PROTOCOL *This,
1306 IN UINT32 MediaId,
1307 IN EFI_LBA Lba,
1308 IN UINTN BufferSize,
1309 OUT VOID *Buffer
1310 )
1311 {
1312 EFI_BLOCK_IO_MEDIA *Media;
1313 BIOS_BLOCK_IO_DEV *BiosBlockIoDev;
1314 EFI_IA32_REGISTER_SET Regs;
1315 UINTN UpperCylinder;
1316 UINTN Temp;
1317 UINTN Cylinder;
1318 UINTN Head;
1319 UINTN Sector;
1320 UINTN NumberOfBlocks;
1321 UINTN TransferByteSize;
1322 UINTN ShortLba;
1323 UINTN CheckLba;
1324 UINTN BlockSize;
1325 BIOS_LEGACY_DRIVE *Bios;
1326 UINTN CarryFlag;
1327 UINTN Retry;
1328 EFI_BLOCK_IO_PROTOCOL *BlockIo;
1329
1330 Media = This->Media;
1331 BlockSize = Media->BlockSize;
1332
1333 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
1334
1335 if (MediaId != Media->MediaId) {
1336 return EFI_MEDIA_CHANGED;
1337 }
1338
1339 if (Lba > Media->LastBlock) {
1340 return EFI_INVALID_PARAMETER;
1341 }
1342
1343 if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
1344 return EFI_INVALID_PARAMETER;
1345 }
1346
1347 if (BufferSize % BlockSize != 0) {
1348 return EFI_BAD_BUFFER_SIZE;
1349 }
1350
1351 if (Buffer == NULL) {
1352 return EFI_INVALID_PARAMETER;
1353 }
1354
1355 if (BufferSize == 0) {
1356 return EFI_SUCCESS;
1357 }
1358
1359 BiosBlockIoDev = BIOS_BLOCK_IO_FROM_THIS (This);
1360 ShortLba = (UINTN) Lba;
1361
1362 while (BufferSize != 0) {
1363 //
1364 // Compute I/O location in Sector, Head, Cylinder format
1365 //
1366 Sector = (ShortLba % BiosBlockIoDev->Bios.MaxSector) + 1;
1367 Temp = ShortLba / BiosBlockIoDev->Bios.MaxSector;
1368 Head = Temp % (BiosBlockIoDev->Bios.MaxHead + 1);
1369 Cylinder = Temp / (BiosBlockIoDev->Bios.MaxHead + 1);
1370
1371 //
1372 // Limit transfer to this Head & Cylinder
1373 //
1374 NumberOfBlocks = BufferSize / BlockSize;
1375 Temp = BiosBlockIoDev->Bios.MaxSector - Sector + 1;
1376 NumberOfBlocks = NumberOfBlocks > Temp ? Temp : NumberOfBlocks;
1377
1378 Retry = 3;
1379 do {
1380 //
1381 // Perform the IO
1382 //
1383 Regs.H.AH = 3;
1384 Regs.H.AL = (UINT8) NumberOfBlocks;
1385 Regs.H.DL = BiosBlockIoDev->Bios.Number;
1386
1387 UpperCylinder = (Cylinder & 0x0f00) >> 2;
1388
1389 CheckLba = Cylinder * (BiosBlockIoDev->Bios.MaxHead + 1) + Head;
1390 CheckLba = CheckLba * BiosBlockIoDev->Bios.MaxSector + Sector - 1;
1391
1392 DEBUG (
1393 (DEBUG_BLKIO,
1394 "RLD: LBA %x (%x), Sector %x (%x), Head %x (%x), Cyl %x, UCyl %x\n",
1395 ShortLba,
1396 CheckLba,
1397 Sector,
1398 BiosBlockIoDev->Bios.MaxSector,
1399 Head,
1400 BiosBlockIoDev->Bios.MaxHead,
1401 Cylinder,
1402 UpperCylinder)
1403 );
1404 ASSERT (CheckLba == ShortLba);
1405
1406 Regs.H.CL = (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff));
1407 Regs.H.DH = (UINT8) (Head & 0x3f);
1408 Regs.H.CH = (UINT8) (Cylinder & 0xff);
1409
1410 Regs.X.BX = EFI_OFFSET (mEdd11Buffer);
1411 Regs.X.ES = EFI_SEGMENT (mEdd11Buffer);
1412
1413 TransferByteSize = NumberOfBlocks * BlockSize;
1414 CopyMem (mEdd11Buffer, Buffer, TransferByteSize);
1415
1416 DEBUG (
1417 (DEBUG_BLKIO,
1418 "INT 13h: AX:(03%02x) DX:(%02x%02x) CX:(%02x%02x) BX:(%04x) ES:(%04x)\n",
1419 Regs.H.AL,
1420 (UINT8) (Head & 0x3f),
1421 Regs.H.DL,
1422 (UINT8) (Cylinder & 0xff),
1423 (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff)),
1424 EFI_OFFSET (mEdd11Buffer),
1425 EFI_SEGMENT (mEdd11Buffer))
1426 );
1427
1428 CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
1429 DEBUG (
1430 (
1431 DEBUG_BLKIO, "BiosWriteLegacyDrive: INT 13 03 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number,
1432 CarryFlag, Regs.H.AH
1433 )
1434 );
1435 Retry--;
1436 } while (CarryFlag != 0 && Retry != 0 && Regs.H.AH != BIOS_DISK_CHANGED);
1437
1438 Media->MediaPresent = TRUE;
1439 if (CarryFlag != 0) {
1440 //
1441 // Return Error Status
1442 //
1443 BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
1444 if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
1445 Media->MediaId++;
1446 Bios = &BiosBlockIoDev->Bios;
1447 if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
1448 if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
1449 Media->LastBlock = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
1450 Media->BlockSize = (UINT32) Bios->Parameters.BytesPerSector;
1451 } else {
1452 //
1453 // Legacy Interfaces
1454 //
1455 Media->LastBlock = (Bios->MaxHead + 1) * Bios->MaxSector * (Bios->MaxCylinder + 1) - 1;
1456 Media->BlockSize = 512;
1457 }
1458 //
1459 // If the size of the media changed we need to reset the disk geometry
1460 //
1461 Media->ReadOnly = FALSE;
1462 gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
1463 gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
1464 return EFI_MEDIA_CHANGED;
1465 }
1466 } else if (BiosBlockIoDev->Bios.ErrorCode == BIOS_WRITE_PROTECTED) {
1467 Media->ReadOnly = TRUE;
1468 return EFI_WRITE_PROTECTED;
1469 }
1470
1471 if (Media->RemovableMedia) {
1472 Media->MediaPresent = FALSE;
1473 }
1474
1475 return EFI_DEVICE_ERROR;
1476 }
1477
1478 Media->ReadOnly = FALSE;
1479 ShortLba = ShortLba + NumberOfBlocks;
1480 BufferSize = BufferSize - TransferByteSize;
1481 Buffer = (VOID *) ((UINT8 *) Buffer + TransferByteSize);
1482 }
1483
1484 return EFI_SUCCESS;
1485 }