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