]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIo.c
Code scrub for DiskIo, Partition & Unicode Collation
[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
235 Status = gBS->CloseProtocol (
236 ControllerHandle,
237 &gEfiBlockIoProtocolGuid,
238 This->DriverBindingHandle,
239 ControllerHandle
240 );
241 }
242
243 if (!EFI_ERROR (Status)) {
244 FreePool (Private);
245 }
246
247 return Status;
248 }
249
250
251
252 /**
253 Read BufferSize bytes from Offset into Buffer.
254 Reads may support reads that are not aligned on
255 sector boundaries. There are three cases:
256 UnderRun - The first byte is not on a sector boundary or the read request is
257 less than a sector in length.
258 Aligned - A read of N contiguous sectors.
259 OverRun - The last byte is not on a sector boundary.
260
261 @param This Protocol instance pointer.
262 @param MediaId Id of the media, changes every time the media is replaced.
263 @param Offset The starting byte offset to read from
264 @param BufferSize Size of Buffer
265 @param Buffer Buffer containing read data
266
267 @retval EFI_SUCCESS The data was read correctly from the device.
268 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
269 @retval EFI_NO_MEDIA There is no media in the device.
270 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
271 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
272 valid for the device.
273
274 **/
275 EFI_STATUS
276 EFIAPI
277 DiskIoReadDisk (
278 IN EFI_DISK_IO_PROTOCOL *This,
279 IN UINT32 MediaId,
280 IN UINT64 Offset,
281 IN UINTN BufferSize,
282 OUT VOID *Buffer
283 )
284 {
285 EFI_STATUS Status;
286 DISK_IO_PRIVATE_DATA *Private;
287 EFI_BLOCK_IO_PROTOCOL *BlockIo;
288 EFI_BLOCK_IO_MEDIA *Media;
289 UINT32 BlockSize;
290 UINT64 Lba;
291 UINT64 OverRunLba;
292 UINT32 UnderRun;
293 UINT32 OverRun;
294 BOOLEAN TransactionComplete;
295 UINTN WorkingBufferSize;
296 UINT8 *WorkingBuffer;
297 UINTN Length;
298 UINT8 *Data;
299 UINT8 *PreData;
300 UINTN IsBufferAligned;
301 UINTN DataBufferSize;
302 BOOLEAN LastRead;
303
304 Private = DISK_IO_PRIVATE_DATA_FROM_THIS (This);
305
306 BlockIo = Private->BlockIo;
307 Media = BlockIo->Media;
308 BlockSize = Media->BlockSize;
309
310 if (Media->MediaId != MediaId) {
311 return EFI_MEDIA_CHANGED;
312 }
313
314 WorkingBuffer = Buffer;
315 WorkingBufferSize = BufferSize;
316
317 //
318 // Allocate a temporary buffer for operation
319 //
320 DataBufferSize = BlockSize * DATA_BUFFER_BLOCK_NUM;
321
322 if (Media->IoAlign > 1) {
323 PreData = AllocatePool (DataBufferSize + Media->IoAlign);
324 Data = PreData - ((UINTN) PreData & (Media->IoAlign - 1)) + Media->IoAlign;
325 } else {
326 PreData = AllocatePool (DataBufferSize);
327 Data = PreData;
328 }
329
330 if (PreData == NULL) {
331 return EFI_OUT_OF_RESOURCES;
332 }
333
334 Lba = DivU64x32Remainder (Offset, BlockSize, &UnderRun);
335
336 Length = BlockSize - UnderRun;
337 TransactionComplete = FALSE;
338
339 Status = EFI_SUCCESS;
340 if (UnderRun != 0) {
341 //
342 // Offset starts in the middle of an Lba, so read the entire block.
343 //
344 Status = BlockIo->ReadBlocks (
345 BlockIo,
346 MediaId,
347 Lba,
348 BlockSize,
349 Data
350 );
351
352 if (EFI_ERROR (Status)) {
353 goto Done;
354 }
355
356 if (Length > BufferSize) {
357 Length = BufferSize;
358 TransactionComplete = TRUE;
359 }
360
361 CopyMem (WorkingBuffer, Data + UnderRun, Length);
362
363 WorkingBuffer += Length;
364
365 WorkingBufferSize -= Length;
366 if (WorkingBufferSize == 0) {
367 goto Done;
368 }
369
370 Lba += 1;
371 }
372
373 OverRunLba = Lba + DivU64x32Remainder (WorkingBufferSize, BlockSize, &OverRun);
374
375 if (!TransactionComplete && WorkingBufferSize >= BlockSize) {
376 //
377 // If the DiskIo maps directly to a BlockIo device do the read.
378 //
379 if (OverRun != 0) {
380 WorkingBufferSize -= OverRun;
381 }
382 //
383 // Check buffer alignment
384 //
385 IsBufferAligned = (UINTN) WorkingBuffer & (UINTN) (Media->IoAlign - 1);
386
387 if (Media->IoAlign <= 1 || IsBufferAligned == 0) {
388 //
389 // Alignment is satisfied, so read them together
390 //
391 Status = BlockIo->ReadBlocks (
392 BlockIo,
393 MediaId,
394 Lba,
395 WorkingBufferSize,
396 WorkingBuffer
397 );
398
399 if (EFI_ERROR (Status)) {
400 goto Done;
401 }
402
403 WorkingBuffer += WorkingBufferSize;
404
405 } else {
406 //
407 // Use the allocated buffer instead of the original buffer
408 // to avoid alignment issue.
409 // Here, the allocated buffer (8-byte align) can satisfy the alignment
410 //
411 LastRead = FALSE;
412 do {
413 if (WorkingBufferSize <= DataBufferSize) {
414 //
415 // It is the last calling to readblocks in this loop
416 //
417 DataBufferSize = WorkingBufferSize;
418 LastRead = TRUE;
419 }
420
421 Status = BlockIo->ReadBlocks (
422 BlockIo,
423 MediaId,
424 Lba,
425 DataBufferSize,
426 Data
427 );
428 if (EFI_ERROR (Status)) {
429 goto Done;
430 }
431
432 CopyMem (WorkingBuffer, Data, DataBufferSize);
433 WorkingBufferSize -= DataBufferSize;
434 WorkingBuffer += DataBufferSize;
435 Lba += DATA_BUFFER_BLOCK_NUM;
436 } while (!LastRead);
437 }
438 }
439
440 if (!TransactionComplete && OverRun != 0) {
441 //
442 // Last read is not a complete block.
443 //
444 Status = BlockIo->ReadBlocks (
445 BlockIo,
446 MediaId,
447 OverRunLba,
448 BlockSize,
449 Data
450 );
451
452 if (EFI_ERROR (Status)) {
453 goto Done;
454 }
455
456 CopyMem (WorkingBuffer, Data, OverRun);
457 }
458
459 Done:
460 if (PreData != NULL) {
461 FreePool (PreData);
462 }
463
464 return Status;
465 }
466
467
468 /**
469 Writes BufferSize bytes from Buffer into Offset.
470 Writes may require a read modify write to support writes that are not
471 aligned on sector boundaries. There are three cases:
472 UnderRun - The first byte is not on a sector boundary or the write request
473 is less than a sector in length. Read modify write is required.
474 Aligned - A write of N contiguous sectors.
475 OverRun - The last byte is not on a sector boundary. Read modified write
476 required.
477
478 @param This Protocol instance pointer.
479 @param MediaId Id of the media, changes every time the media is replaced.
480 @param Offset The starting byte offset to read from
481 @param BufferSize Size of Buffer
482 @param Buffer Buffer containing read data
483
484 @retval EFI_SUCCESS The data was written correctly to the device.
485 @retval EFI_WRITE_PROTECTED The device can not be written to.
486 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
487 @retval EFI_NO_MEDIA There is no media in the device.
488 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
489 @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not
490 valid for the device.
491
492 **/
493 EFI_STATUS
494 EFIAPI
495 DiskIoWriteDisk (
496 IN EFI_DISK_IO_PROTOCOL *This,
497 IN UINT32 MediaId,
498 IN UINT64 Offset,
499 IN UINTN BufferSize,
500 IN VOID *Buffer
501 )
502 {
503 EFI_STATUS Status;
504 DISK_IO_PRIVATE_DATA *Private;
505 EFI_BLOCK_IO_PROTOCOL *BlockIo;
506 EFI_BLOCK_IO_MEDIA *Media;
507 UINT32 BlockSize;
508 UINT64 Lba;
509 UINT64 OverRunLba;
510 UINT32 UnderRun;
511 UINT32 OverRun;
512 BOOLEAN TransactionComplete;
513 UINTN WorkingBufferSize;
514 UINT8 *WorkingBuffer;
515 UINTN Length;
516 UINT8 *Data;
517 UINT8 *PreData;
518 UINTN IsBufferAligned;
519 UINTN DataBufferSize;
520 BOOLEAN LastWrite;
521
522 Private = DISK_IO_PRIVATE_DATA_FROM_THIS (This);
523
524 BlockIo = Private->BlockIo;
525 Media = BlockIo->Media;
526 BlockSize = Media->BlockSize;
527
528 if (Media->ReadOnly) {
529 return EFI_WRITE_PROTECTED;
530 }
531
532 if (Media->MediaId != MediaId) {
533 return EFI_MEDIA_CHANGED;
534 }
535
536 DataBufferSize = BlockSize * DATA_BUFFER_BLOCK_NUM;
537
538 if (Media->IoAlign > 1) {
539 PreData = AllocatePool (DataBufferSize + Media->IoAlign);
540 Data = PreData - ((UINTN) PreData & (Media->IoAlign - 1)) + Media->IoAlign;
541 } else {
542 PreData = AllocatePool (DataBufferSize);
543 Data = PreData;
544 }
545
546 if (PreData == NULL) {
547 return EFI_OUT_OF_RESOURCES;
548 }
549
550 WorkingBuffer = Buffer;
551 WorkingBufferSize = BufferSize;
552
553 Lba = DivU64x32Remainder (Offset, BlockSize, &UnderRun);
554
555 Length = BlockSize - UnderRun;
556 TransactionComplete = FALSE;
557
558 Status = EFI_SUCCESS;
559 if (UnderRun != 0) {
560 //
561 // Offset starts in the middle of an Lba, so do read modify write.
562 //
563 Status = BlockIo->ReadBlocks (
564 BlockIo,
565 MediaId,
566 Lba,
567 BlockSize,
568 Data
569 );
570
571 if (EFI_ERROR (Status)) {
572 goto Done;
573 }
574
575 if (Length > BufferSize) {
576 Length = BufferSize;
577 TransactionComplete = TRUE;
578 }
579
580 CopyMem (Data + UnderRun, WorkingBuffer, Length);
581
582 Status = BlockIo->WriteBlocks (
583 BlockIo,
584 MediaId,
585 Lba,
586 BlockSize,
587 Data
588 );
589 if (EFI_ERROR (Status)) {
590 goto Done;
591 }
592
593 WorkingBuffer += Length;
594 WorkingBufferSize -= Length;
595 if (WorkingBufferSize == 0) {
596 goto Done;
597 }
598
599 Lba += 1;
600 }
601
602 OverRunLba = Lba + DivU64x32Remainder (WorkingBufferSize, BlockSize, &OverRun);
603
604 if (!TransactionComplete && WorkingBufferSize >= BlockSize) {
605 //
606 // If the DiskIo maps directly to a BlockIo device do the write.
607 //
608 if (OverRun != 0) {
609 WorkingBufferSize -= OverRun;
610 }
611 //
612 // Check buffer alignment
613 //
614 IsBufferAligned = (UINTN) WorkingBuffer & (UINTN) (Media->IoAlign - 1);
615
616 if (Media->IoAlign <= 1 || IsBufferAligned == 0) {
617 //
618 // Alignment is satisfied, so write them together
619 //
620 Status = BlockIo->WriteBlocks (
621 BlockIo,
622 MediaId,
623 Lba,
624 WorkingBufferSize,
625 WorkingBuffer
626 );
627
628 if (EFI_ERROR (Status)) {
629 goto Done;
630 }
631
632 WorkingBuffer += WorkingBufferSize;
633
634 } else {
635 //
636 // The buffer parameter is not aligned with the request
637 // So use the allocated instead.
638 // It can fit almost all the cases.
639 //
640 LastWrite = FALSE;
641 do {
642 if (WorkingBufferSize <= DataBufferSize) {
643 //
644 // It is the last calling to writeblocks in this loop
645 //
646 DataBufferSize = WorkingBufferSize;
647 LastWrite = TRUE;
648 }
649
650 CopyMem (Data, WorkingBuffer, DataBufferSize);
651 Status = BlockIo->WriteBlocks (
652 BlockIo,
653 MediaId,
654 Lba,
655 DataBufferSize,
656 Data
657 );
658 if (EFI_ERROR (Status)) {
659 goto Done;
660 }
661
662 WorkingBufferSize -= DataBufferSize;
663 WorkingBuffer += DataBufferSize;
664 Lba += DATA_BUFFER_BLOCK_NUM;
665 } while (!LastWrite);
666 }
667 }
668
669 if (!TransactionComplete && OverRun != 0) {
670 //
671 // Last bit is not a complete block, so do a read modify write.
672 //
673 Status = BlockIo->ReadBlocks (
674 BlockIo,
675 MediaId,
676 OverRunLba,
677 BlockSize,
678 Data
679 );
680
681 if (EFI_ERROR (Status)) {
682 goto Done;
683 }
684
685 CopyMem (Data, WorkingBuffer, OverRun);
686
687 Status = BlockIo->WriteBlocks (
688 BlockIo,
689 MediaId,
690 OverRunLba,
691 BlockSize,
692 Data
693 );
694 if (EFI_ERROR (Status)) {
695 goto Done;
696 }
697 }
698
699 Done:
700 if (PreData != NULL) {
701 FreePool (PreData);
702 }
703
704 return Status;
705 }
706
707
708 /**
709 The user Entry Point for module DiskIo. The user code starts with this function.
710
711 @param[in] ImageHandle The firmware allocated handle for the EFI image.
712 @param[in] SystemTable A pointer to the EFI System Table.
713
714 @retval EFI_SUCCESS The entry point is executed successfully.
715 @retval other Some error occurs when executing this entry point.
716
717 **/
718 EFI_STATUS
719 EFIAPI
720 InitializeDiskIo (
721 IN EFI_HANDLE ImageHandle,
722 IN EFI_SYSTEM_TABLE *SystemTable
723 )
724 {
725 EFI_STATUS Status;
726
727 //
728 // Install driver model protocol(s).
729 //
730 Status = EfiLibInstallDriverBindingComponentName2 (
731 ImageHandle,
732 SystemTable,
733 &gDiskIoDriverBinding,
734 ImageHandle,
735 &gDiskIoComponentName,
736 &gDiskIoComponentName2
737 );
738 ASSERT_EFI_ERROR (Status);
739
740
741 return Status;
742 }
743