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