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