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