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