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