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