]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Universal/Disk/DiskIo/Dxe/diskio.c
1. Add the fix for the following Bugs:
[mirror_edk2.git] / EdkModulePkg / Universal / Disk / DiskIo / Dxe / diskio.c
CommitLineData
511710d6 1/*++\r
2\r
3Copyright (c) 2006, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13\r
14 DiskIo.c\r
15\r
16Abstract:\r
17\r
18 DiskIo driver that layers it's self on every Block IO protocol in the system.\r
19 DiskIo converts a block oriented device to a byte oriented device.\r
20\r
21 ReadDisk may have to do reads that are not aligned on sector boundaries.\r
22 There are three cases:\r
23\r
24 UnderRun - The first byte is not on a sector boundary or the read request is\r
25 less than a sector in length.\r
26\r
27 Aligned - A read of N contiguous sectors.\r
28\r
29 OverRun - The last byte is not on a sector boundary.\r
30\r
31--*/\r
32\r
33#include "DiskIo.h"\r
34\r
35//\r
36// Prototypes\r
37// Driver model protocol interface\r
38//\r
39EFI_STATUS\r
40EFIAPI\r
41DiskIoDriverBindingSupported (\r
42 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
43 IN EFI_HANDLE ControllerHandle,\r
44 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
45 );\r
46\r
47EFI_STATUS\r
48EFIAPI\r
49DiskIoDriverBindingStart (\r
50 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
51 IN EFI_HANDLE ControllerHandle,\r
52 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
53 );\r
54\r
55EFI_STATUS\r
56EFIAPI\r
57DiskIoDriverBindingStop (\r
58 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
59 IN EFI_HANDLE ControllerHandle,\r
60 IN UINTN NumberOfChildren,\r
61 IN EFI_HANDLE *ChildHandleBuffer\r
62 );\r
63\r
64//\r
65// Disk I/O Protocol Interface\r
66//\r
67EFI_STATUS\r
68EFIAPI\r
69DiskIoReadDisk (\r
70 IN EFI_DISK_IO_PROTOCOL *This,\r
71 IN UINT32 MediaId,\r
72 IN UINT64 Offset,\r
73 IN UINTN BufferSize,\r
74 OUT VOID *Buffer\r
75 );\r
76\r
77EFI_STATUS\r
78EFIAPI\r
79DiskIoWriteDisk (\r
80 IN EFI_DISK_IO_PROTOCOL *This,\r
81 IN UINT32 MediaId,\r
82 IN UINT64 Offset,\r
83 IN UINTN BufferSize,\r
84 IN VOID *Buffer\r
85 );\r
86\r
87EFI_DRIVER_BINDING_PROTOCOL gDiskIoDriverBinding = {\r
88 DiskIoDriverBindingSupported,\r
89 DiskIoDriverBindingStart,\r
90 DiskIoDriverBindingStop,\r
91 0x10,\r
92 NULL,\r
93 NULL\r
94};\r
95\r
96DISK_IO_PRIVATE_DATA gDiskIoPrivateDataTemplate = {\r
97 DISK_IO_PRIVATE_DATA_SIGNATURE,\r
98 {\r
99 EFI_DISK_IO_PROTOCOL_REVISION,\r
100 DiskIoReadDisk,\r
101 DiskIoWriteDisk\r
102 },\r
103 NULL\r
104};\r
105\r
106EFI_STATUS\r
107EFIAPI\r
108DiskIoDriverBindingSupported (\r
109 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
110 IN EFI_HANDLE ControllerHandle,\r
111 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
112 )\r
113/*++\r
114\r
115 Routine Description:\r
116 Test to see if this driver supports ControllerHandle. Any ControllerHandle\r
117 than contains a BlockIo protocol can be supported.\r
118\r
119 Arguments:\r
120 This - Protocol instance pointer.\r
121 ControllerHandle - Handle of device to test.\r
122 RemainingDevicePath - Not used.\r
123\r
124 Returns:\r
125 EFI_SUCCESS - This driver supports this device.\r
126 EFI_ALREADY_STARTED - This driver is already running on this device.\r
127 other - This driver does not support this device.\r
128\r
129--*/\r
130{\r
131 EFI_STATUS Status;\r
132 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
133\r
134 //\r
135 // Open the IO Abstraction(s) needed to perform the supported test.\r
136 //\r
137 Status = gBS->OpenProtocol (\r
138 ControllerHandle,\r
139 &gEfiBlockIoProtocolGuid,\r
140 (VOID **) &BlockIo,\r
141 This->DriverBindingHandle,\r
142 ControllerHandle,\r
143 EFI_OPEN_PROTOCOL_BY_DRIVER\r
144 );\r
145 if (EFI_ERROR (Status)) {\r
146 return Status;\r
147 }\r
148 //\r
149 // Close the I/O Abstraction(s) used to perform the supported test.\r
150 //\r
151 gBS->CloseProtocol (\r
152 ControllerHandle,\r
153 &gEfiBlockIoProtocolGuid,\r
154 This->DriverBindingHandle,\r
155 ControllerHandle\r
156 );\r
157 return EFI_SUCCESS;\r
158}\r
159\r
160EFI_STATUS\r
161EFIAPI\r
162DiskIoDriverBindingStart (\r
163 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
164 IN EFI_HANDLE ControllerHandle,\r
165 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
166 )\r
167/*++\r
168\r
169 Routine Description:\r
170 Start this driver on ControllerHandle by opening a Block IO protocol and\r
171 installing a Disk IO protocol on ControllerHandle.\r
172\r
173 Arguments:\r
174 This - Protocol instance pointer.\r
175 ControllerHandle - Handle of device to bind driver to.\r
176 RemainingDevicePath - Not used, always produce all possible children.\r
177\r
178 Returns:\r
179 EFI_SUCCESS - This driver is added to ControllerHandle.\r
180 EFI_ALREADY_STARTED - This driver is already running on ControllerHandle.\r
181 other - This driver does not support this device.\r
182\r
183--*/\r
184{\r
185 EFI_STATUS Status;\r
186 DISK_IO_PRIVATE_DATA *Private;\r
187\r
188 Private = NULL;\r
189\r
190 //\r
191 // Connect to the Block IO interface on ControllerHandle.\r
192 //\r
193 Status = gBS->OpenProtocol (\r
194 ControllerHandle,\r
195 &gEfiBlockIoProtocolGuid,\r
196 (VOID **) &gDiskIoPrivateDataTemplate.BlockIo,\r
197 This->DriverBindingHandle,\r
198 ControllerHandle,\r
199 EFI_OPEN_PROTOCOL_BY_DRIVER\r
200 );\r
201 if (EFI_ERROR (Status)) {\r
202 return Status;\r
203 }\r
204 //\r
205 // Initialize the Disk IO device instance.\r
206 //\r
207 Private = AllocateCopyPool (sizeof (DISK_IO_PRIVATE_DATA), &gDiskIoPrivateDataTemplate);\r
208 if (Private == NULL) {\r
209 Status = EFI_OUT_OF_RESOURCES;\r
210 goto ErrorExit;\r
211 }\r
212 //\r
213 // Install protocol interfaces for the Disk IO device.\r
214 //\r
215 Status = gBS->InstallProtocolInterface (\r
216 &ControllerHandle,\r
217 &gEfiDiskIoProtocolGuid,\r
218 EFI_NATIVE_INTERFACE,\r
219 &Private->DiskIo\r
220 );\r
221\r
222ErrorExit:\r
223 if (EFI_ERROR (Status)) {\r
224\r
225 if (Private != NULL) {\r
226 gBS->FreePool (Private);\r
227 }\r
228\r
229 gBS->CloseProtocol (\r
230 ControllerHandle,\r
231 &gEfiBlockIoProtocolGuid,\r
232 This->DriverBindingHandle,\r
233 ControllerHandle\r
234 );\r
235 }\r
236\r
237 return Status;\r
238}\r
239\r
240EFI_STATUS\r
241EFIAPI\r
242DiskIoDriverBindingStop (\r
243 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
244 IN EFI_HANDLE ControllerHandle,\r
245 IN UINTN NumberOfChildren,\r
246 IN EFI_HANDLE *ChildHandleBuffer\r
247 )\r
248/*++\r
249\r
250 Routine Description:\r
251 Stop this driver on ControllerHandle by removing Disk IO protocol and closing\r
252 the Block IO protocol on ControllerHandle.\r
253\r
254 Arguments:\r
255 This - Protocol instance pointer.\r
256 ControllerHandle - Handle of device to stop driver on.\r
257 NumberOfChildren - Not used.\r
258 ChildHandleBuffer - Not used.\r
259\r
260 Returns:\r
261 EFI_SUCCESS - This driver is removed ControllerHandle.\r
262 other - This driver was not removed from this device.\r
263 EFI_UNSUPPORTED\r
264\r
265--*/\r
266{\r
267 EFI_STATUS Status;\r
268 EFI_DISK_IO_PROTOCOL *DiskIo;\r
269 DISK_IO_PRIVATE_DATA *Private;\r
270\r
271 //\r
272 // Get our context back.\r
273 //\r
274 Status = gBS->OpenProtocol (\r
275 ControllerHandle,\r
276 &gEfiDiskIoProtocolGuid,\r
277 (VOID **) &DiskIo,\r
278 This->DriverBindingHandle,\r
279 ControllerHandle,\r
280 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
281 );\r
282 if (EFI_ERROR (Status)) {\r
283 return EFI_UNSUPPORTED;\r
284 }\r
285\r
286 Private = DISK_IO_PRIVATE_DATA_FROM_THIS (DiskIo);\r
287\r
288 Status = gBS->UninstallProtocolInterface (\r
289 ControllerHandle,\r
290 &gEfiDiskIoProtocolGuid,\r
291 &Private->DiskIo\r
292 );\r
293 if (!EFI_ERROR (Status)) {\r
294\r
295 Status = gBS->CloseProtocol (\r
296 ControllerHandle,\r
297 &gEfiBlockIoProtocolGuid,\r
298 This->DriverBindingHandle,\r
299 ControllerHandle\r
300 );\r
301 }\r
302\r
303 if (!EFI_ERROR (Status)) {\r
304 gBS->FreePool (Private);\r
305 }\r
306\r
307 return Status;\r
308}\r
309\r
310EFI_STATUS\r
311EFIAPI\r
312DiskIoReadDisk (\r
313 IN EFI_DISK_IO_PROTOCOL *This,\r
314 IN UINT32 MediaId,\r
315 IN UINT64 Offset,\r
316 IN UINTN BufferSize,\r
317 OUT VOID *Buffer\r
318 )\r
319/*++\r
320\r
321 Routine Description:\r
322 Read BufferSize bytes from Offset into Buffer.\r
323\r
324 Reads may support reads that are not aligned on\r
325 sector boundaries. There are three cases:\r
326\r
327 UnderRun - The first byte is not on a sector boundary or the read request is\r
328 less than a sector in length.\r
329\r
330 Aligned - A read of N contiguous sectors.\r
331\r
332 OverRun - The last byte is not on a sector boundary.\r
333\r
334\r
335 Arguments:\r
336 This - Protocol instance pointer.\r
337 MediaId - Id of the media, changes every time the media is replaced.\r
338 Offset - The starting byte offset to read from.\r
339 BufferSize - Size of Buffer.\r
340 Buffer - Buffer containing read data.\r
341\r
342 Returns:\r
343 EFI_SUCCESS - The data was read correctly from the device.\r
344 EFI_DEVICE_ERROR - The device reported an error while performing the read.\r
345 EFI_NO_MEDIA - There is no media in the device.\r
346 EFI_MEDIA_CHNAGED - The MediaId does not matched the current device.\r
347 EFI_INVALID_PARAMETER - The read request contains device addresses that are not\r
348 valid for the device.\r
349 EFI_OUT_OF_RESOURCES\r
350\r
351--*/\r
352{\r
353 EFI_STATUS Status;\r
354 DISK_IO_PRIVATE_DATA *Private;\r
355 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
356 EFI_BLOCK_IO_MEDIA *Media;\r
357 UINT32 BlockSize;\r
358 UINT64 Lba;\r
359 UINT64 OverRunLba;\r
360 UINT32 UnderRun;\r
361 UINT32 OverRun;\r
362 BOOLEAN TransactionComplete;\r
363 UINTN WorkingBufferSize;\r
364 UINT8 *WorkingBuffer;\r
365 UINTN Length;\r
366 UINT8 *Data;\r
367 UINT8 *PreData;\r
368 UINTN IsBufferAligned;\r
369 UINTN DataBufferSize;\r
370 BOOLEAN LastRead;\r
371\r
372 Private = DISK_IO_PRIVATE_DATA_FROM_THIS (This);\r
373\r
374 BlockIo = Private->BlockIo;\r
375 Media = BlockIo->Media;\r
376 BlockSize = Media->BlockSize;\r
377\r
378 if (Media->MediaId != MediaId) {\r
379 return EFI_MEDIA_CHANGED;\r
380 }\r
381\r
382 WorkingBuffer = Buffer;\r
383 WorkingBufferSize = BufferSize;\r
384\r
385 //\r
386 // Allocate a temporary buffer for operation\r
387 //\r
388 DataBufferSize = BlockSize * DATA_BUFFER_BLOCK_NUM;\r
389\r
390 if (Media->IoAlign > 1) {\r
391 PreData = AllocatePool (DataBufferSize + Media->IoAlign);\r
392 Data = PreData - ((UINTN) PreData & (Media->IoAlign - 1)) + Media->IoAlign;\r
393 } else {\r
394 PreData = AllocatePool (DataBufferSize);\r
395 Data = PreData;\r
396 }\r
397\r
398 if (PreData == NULL) {\r
399 return EFI_OUT_OF_RESOURCES;\r
400 }\r
401\r
402 Lba = DivU64x32Remainder (Offset, BlockSize, &UnderRun);\r
403\r
404 Length = BlockSize - UnderRun;\r
405 TransactionComplete = FALSE;\r
406\r
407 Status = EFI_SUCCESS;\r
408 if (UnderRun != 0) {\r
409 //\r
410 // Offset starts in the middle of an Lba, so read the entire block.\r
411 //\r
412 Status = BlockIo->ReadBlocks (\r
413 BlockIo,\r
414 MediaId,\r
415 Lba,\r
416 BlockSize,\r
417 Data\r
418 );\r
419\r
420 if (EFI_ERROR (Status)) {\r
421 goto Done;\r
422 }\r
423\r
424 if (Length > BufferSize) {\r
425 Length = BufferSize;\r
426 TransactionComplete = TRUE;\r
427 }\r
428\r
429 CopyMem (WorkingBuffer, Data + UnderRun, Length);\r
430\r
431 WorkingBuffer += Length;\r
432\r
433 WorkingBufferSize -= Length;\r
434 if (WorkingBufferSize == 0) {\r
435 goto Done;\r
436 }\r
437\r
438 Lba += 1;\r
439 }\r
440\r
441 OverRunLba = Lba + DivU64x32Remainder (WorkingBufferSize, BlockSize, &OverRun);\r
442\r
443 if (!TransactionComplete && WorkingBufferSize >= BlockSize) {\r
444 //\r
445 // If the DiskIo maps directly to a BlockIo device do the read.\r
446 //\r
447 if (OverRun != 0) {\r
448 WorkingBufferSize -= OverRun;\r
449 }\r
450 //\r
451 // Check buffer alignment\r
452 //\r
453 IsBufferAligned = (UINTN) WorkingBuffer & (UINTN) (Media->IoAlign - 1);\r
454\r
455 if (Media->IoAlign <= 1 || IsBufferAligned == 0) {\r
456 //\r
457 // Alignment is satisfied, so read them together\r
458 //\r
459 Status = BlockIo->ReadBlocks (\r
460 BlockIo,\r
461 MediaId,\r
462 Lba,\r
463 WorkingBufferSize,\r
464 WorkingBuffer\r
465 );\r
466\r
467 if (EFI_ERROR (Status)) {\r
468 goto Done;\r
469 }\r
470\r
471 WorkingBuffer += WorkingBufferSize;\r
472\r
473 } else {\r
474 //\r
475 // Use the allocated buffer instead of the original buffer\r
476 // to avoid alignment issue.\r
477 // Here, the allocated buffer (8-byte align) can satisfy the alignment\r
478 //\r
479 LastRead = FALSE;\r
480 do {\r
481 if (WorkingBufferSize <= DataBufferSize) {\r
482 //\r
483 // It is the last calling to readblocks in this loop\r
484 //\r
485 DataBufferSize = WorkingBufferSize;\r
486 LastRead = TRUE;\r
487 }\r
488\r
489 Status = BlockIo->ReadBlocks (\r
490 BlockIo,\r
491 MediaId,\r
492 Lba,\r
493 DataBufferSize,\r
494 Data\r
495 );\r
496 if (EFI_ERROR (Status)) {\r
497 goto Done;\r
498 }\r
499\r
500 CopyMem (WorkingBuffer, Data, DataBufferSize);\r
501 WorkingBufferSize -= DataBufferSize;\r
502 WorkingBuffer += DataBufferSize;\r
503 Lba += DATA_BUFFER_BLOCK_NUM;\r
504 } while (!LastRead);\r
505 }\r
506 }\r
507\r
508 if (!TransactionComplete && OverRun != 0) {\r
509 //\r
510 // Last read is not a complete block.\r
511 //\r
512 Status = BlockIo->ReadBlocks (\r
513 BlockIo,\r
514 MediaId,\r
515 OverRunLba,\r
516 BlockSize,\r
517 Data\r
518 );\r
519\r
520 if (EFI_ERROR (Status)) {\r
521 goto Done;\r
522 }\r
523\r
524 CopyMem (WorkingBuffer, Data, OverRun);\r
525 }\r
526\r
527Done:\r
528 if (PreData != NULL) {\r
529 gBS->FreePool (PreData);\r
530 }\r
531\r
532 return Status;\r
533}\r
534\r
535EFI_STATUS\r
536EFIAPI\r
537DiskIoWriteDisk (\r
538 IN EFI_DISK_IO_PROTOCOL *This,\r
539 IN UINT32 MediaId,\r
540 IN UINT64 Offset,\r
541 IN UINTN BufferSize,\r
542 IN VOID *Buffer\r
543 )\r
544/*++\r
545\r
546 Routine Description:\r
547 Read BufferSize bytes from Offset into Buffer.\r
548\r
549 Writes may require a read modify write to support writes that are not\r
550 aligned on sector boundaries. There are three cases:\r
551\r
552 UnderRun - The first byte is not on a sector boundary or the write request\r
553 is less than a sector in length. Read modify write is required.\r
554\r
555 Aligned - A write of N contiguous sectors.\r
556\r
557 OverRun - The last byte is not on a sector boundary. Read modified write\r
558 required.\r
559\r
560 Arguments:\r
561 This - Protocol instance pointer.\r
562 MediaId - Id of the media, changes every time the media is replaced.\r
563 Offset - The starting byte offset to read from.\r
564 BufferSize - Size of Buffer.\r
565 Buffer - Buffer containing read data.\r
566\r
567 Returns:\r
568 EFI_SUCCESS - The data was written correctly to the device.\r
569 EFI_WRITE_PROTECTED - The device can not be written to.\r
570 EFI_DEVICE_ERROR - The device reported an error while performing the write.\r
571 EFI_NO_MEDIA - There is no media in the device.\r
572 EFI_MEDIA_CHNAGED - The MediaId does not matched the current device.\r
573 EFI_INVALID_PARAMETER - The write request contains device addresses that are not\r
574 valid for the device.\r
575 EFI_OUT_OF_RESOURCES\r
576\r
577--*/\r
578{\r
579 EFI_STATUS Status;\r
580 DISK_IO_PRIVATE_DATA *Private;\r
581 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
582 EFI_BLOCK_IO_MEDIA *Media;\r
583 UINT32 BlockSize;\r
584 UINT64 Lba;\r
585 UINT64 OverRunLba;\r
586 UINT32 UnderRun;\r
587 UINT32 OverRun;\r
588 BOOLEAN TransactionComplete;\r
589 UINTN WorkingBufferSize;\r
590 UINT8 *WorkingBuffer;\r
591 UINTN Length;\r
592 UINT8 *Data;\r
593 UINT8 *PreData;\r
594 UINTN IsBufferAligned;\r
595 UINTN DataBufferSize;\r
596 BOOLEAN LastWrite;\r
597\r
598 Private = DISK_IO_PRIVATE_DATA_FROM_THIS (This);\r
599\r
600 BlockIo = Private->BlockIo;\r
601 Media = BlockIo->Media;\r
602 BlockSize = Media->BlockSize;\r
603\r
604 if (Media->ReadOnly) {\r
605 return EFI_WRITE_PROTECTED;\r
606 }\r
607\r
608 if (Media->MediaId != MediaId) {\r
609 return EFI_MEDIA_CHANGED;\r
610 }\r
611\r
612 DataBufferSize = BlockSize * DATA_BUFFER_BLOCK_NUM;\r
613\r
614 if (Media->IoAlign > 1) {\r
615 PreData = AllocatePool (DataBufferSize + Media->IoAlign);\r
616 Data = PreData - ((UINTN) PreData & (Media->IoAlign - 1)) + Media->IoAlign;\r
617 } else {\r
618 PreData = AllocatePool (DataBufferSize);\r
619 Data = PreData;\r
620 }\r
621\r
622 if (PreData == NULL) {\r
623 return EFI_OUT_OF_RESOURCES;\r
624 }\r
625\r
626 WorkingBuffer = Buffer;\r
627 WorkingBufferSize = BufferSize;\r
628\r
629 Lba = DivU64x32Remainder (Offset, BlockSize, &UnderRun);\r
630\r
631 Length = BlockSize - UnderRun;\r
632 TransactionComplete = FALSE;\r
633\r
634 Status = EFI_SUCCESS;\r
635 if (UnderRun != 0) {\r
636 //\r
637 // Offset starts in the middle of an Lba, so do read modify write.\r
638 //\r
639 Status = BlockIo->ReadBlocks (\r
640 BlockIo,\r
641 MediaId,\r
642 Lba,\r
643 BlockSize,\r
644 Data\r
645 );\r
646\r
647 if (EFI_ERROR (Status)) {\r
648 goto Done;\r
649 }\r
650\r
651 if (Length > BufferSize) {\r
652 Length = BufferSize;\r
653 TransactionComplete = TRUE;\r
654 }\r
655\r
656 CopyMem (Data + UnderRun, WorkingBuffer, Length);\r
657\r
658 Status = BlockIo->WriteBlocks (\r
659 BlockIo,\r
660 MediaId,\r
661 Lba,\r
662 BlockSize,\r
663 Data\r
664 );\r
665 if (EFI_ERROR (Status)) {\r
666 goto Done;\r
667 }\r
668\r
669 WorkingBuffer += Length;\r
670 WorkingBufferSize -= Length;\r
671 if (WorkingBufferSize == 0) {\r
672 goto Done;\r
673 }\r
674\r
675 Lba += 1;\r
676 }\r
677\r
678 OverRunLba = Lba + DivU64x32Remainder (WorkingBufferSize, BlockSize, &OverRun);\r
679\r
680 if (!TransactionComplete && WorkingBufferSize >= BlockSize) {\r
681 //\r
682 // If the DiskIo maps directly to a BlockIo device do the write.\r
683 //\r
684 if (OverRun != 0) {\r
685 WorkingBufferSize -= OverRun;\r
686 }\r
687 //\r
688 // Check buffer alignment\r
689 //\r
690 IsBufferAligned = (UINTN) WorkingBuffer & (UINTN) (Media->IoAlign - 1);\r
691\r
692 if (Media->IoAlign <= 1 || IsBufferAligned == 0) {\r
693 //\r
694 // Alignment is satisfied, so write them together\r
695 //\r
696 Status = BlockIo->WriteBlocks (\r
697 BlockIo,\r
698 MediaId,\r
699 Lba,\r
700 WorkingBufferSize,\r
701 WorkingBuffer\r
702 );\r
703\r
704 if (EFI_ERROR (Status)) {\r
705 goto Done;\r
706 }\r
707\r
708 WorkingBuffer += WorkingBufferSize;\r
709\r
710 } else {\r
711 //\r
712 // The buffer parameter is not aligned with the request\r
713 // So use the allocated instead.\r
714 // It can fit almost all the cases.\r
715 //\r
716 LastWrite = FALSE;\r
717 do {\r
718 if (WorkingBufferSize <= DataBufferSize) {\r
719 //\r
720 // It is the last calling to writeblocks in this loop\r
721 //\r
722 DataBufferSize = WorkingBufferSize;\r
723 LastWrite = TRUE;\r
724 }\r
725\r
726 CopyMem (Data, WorkingBuffer, DataBufferSize);\r
727 Status = BlockIo->WriteBlocks (\r
728 BlockIo,\r
729 MediaId,\r
730 Lba,\r
731 DataBufferSize,\r
732 Data\r
733 );\r
734 if (EFI_ERROR (Status)) {\r
735 goto Done;\r
736 }\r
737\r
738 WorkingBufferSize -= DataBufferSize;\r
739 WorkingBuffer += DataBufferSize;\r
740 Lba += DATA_BUFFER_BLOCK_NUM;\r
741 } while (!LastWrite);\r
742 }\r
743 }\r
744\r
745 if (!TransactionComplete && OverRun != 0) {\r
746 //\r
747 // Last bit is not a complete block, so do a read modify write.\r
748 //\r
749 Status = BlockIo->ReadBlocks (\r
750 BlockIo,\r
751 MediaId,\r
752 OverRunLba,\r
753 BlockSize,\r
754 Data\r
755 );\r
756\r
757 if (EFI_ERROR (Status)) {\r
758 goto Done;\r
759 }\r
760\r
761 CopyMem (Data, WorkingBuffer, OverRun);\r
762\r
763 Status = BlockIo->WriteBlocks (\r
764 BlockIo,\r
765 MediaId,\r
766 OverRunLba,\r
767 BlockSize,\r
768 Data\r
769 );\r
770 if (EFI_ERROR (Status)) {\r
771 goto Done;\r
772 }\r
773 }\r
774\r
775Done:\r
776 if (PreData != NULL) {\r
777 gBS->FreePool (PreData);\r
778 }\r
779\r
780 return Status;\r
781}\r