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