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