]> git.proxmox.com Git - mirror_edk2.git/blob - Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbSmmDxe.c
Upload BSD-licensed Vlv2TbltDevicePkg and Vlv2DeviceRefCodePkg to
[mirror_edk2.git] / Vlv2TbltDevicePkg / FvbRuntimeDxe / FvbSmmDxe.c
1 /** @file
2
3 Implement the Firmware Volume Block (FVB) services based on SMM FVB
4 module and install FVB protocol.
5
6 Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved. <BR>
7
8 This program and the accompanying materials are licensed and made available under
9 the terms and conditions of the BSD License that accompanies this distribution.
10 The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php.
12
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15
16
17 **/
18
19 #include "FvbSmmDxe.h"
20
21 EFI_HANDLE mHandle = NULL;
22 EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;
23
24 //
25 // Template structure used when installing FVB protocol.
26 //
27 EFI_FVB_DEVICE mFvbDeviceTemplate = {
28 FVB_DEVICE_SIGNATURE,
29 NULL,
30 {
31 FvbGetAttributes,
32 FvbSetAttributes,
33 FvbGetPhysicalAddress,
34 FvbGetBlockSize,
35 FvbRead,
36 FvbWrite,
37 FvbEraseBlocks,
38 NULL
39 },
40 NULL
41 };
42
43 FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = {
44 {
45 {
46 HARDWARE_DEVICE_PATH,
47 HW_MEMMAP_DP,
48 {
49 (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
50 (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
51 }
52 },
53 EfiMemoryMappedIO,
54 (EFI_PHYSICAL_ADDRESS) 0,
55 (EFI_PHYSICAL_ADDRESS) 0,
56 },
57 {
58 END_DEVICE_PATH_TYPE,
59 END_ENTIRE_DEVICE_PATH_SUBTYPE,
60 {
61 END_DEVICE_PATH_LENGTH,
62 0
63 }
64 }
65 };
66
67 FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = {
68 {
69 {
70 MEDIA_DEVICE_PATH,
71 MEDIA_PIWG_FW_VOL_DP,
72 {
73 (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),
74 (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)
75 }
76 },
77 { 0 }
78 },
79 {
80 END_DEVICE_PATH_TYPE,
81 END_ENTIRE_DEVICE_PATH_SUBTYPE,
82 {
83 END_DEVICE_PATH_LENGTH,
84 0
85 }
86 }
87 };
88
89 /**
90 Initialize the communicate buffer using DataSize and Function.
91
92 The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +
93 DataSize.
94
95 @param[out] CommunicateBuffer The communicate buffer. Caller should free it after use.
96 @param[out] DataPtr Points to the data in the communicate buffer. Caller should not free it.
97 @param[in] DataSize The payload size.
98 @param[in] Function The function number used to initialize the communicate header.
99
100 @retval EFI_INVALID_PARAMETER The data size is too big.
101 @retval EFI_SUCCESS Find the specified variable.
102
103 **/
104 EFI_STATUS
105 InitCommunicateBuffer (
106 OUT VOID **CommunicateBuffer,
107 OUT VOID **DataPtr,
108 IN UINTN DataSize,
109 IN UINTN Function
110 )
111 {
112 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
113 SMM_FVB_COMMUNICATE_FUNCTION_HEADER *SmmFvbFunctionHeader;
114
115 //
116 // The whole buffer size: SMM_COMMUNICATE_HEADER_SIZE + SMM_FVB_COMMUNICATE_HEADER_SIZE + DataSize.
117 //
118 SmmCommunicateHeader = AllocatePool (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_FVB_COMMUNICATE_HEADER_SIZE);
119 ASSERT (SmmCommunicateHeader != NULL);
120
121 //
122 // Prepare data buffer.
123 //
124 CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmFirmwareVolumeBlockProtocolGuid);
125 SmmCommunicateHeader->MessageLength = DataSize + SMM_FVB_COMMUNICATE_HEADER_SIZE;
126
127 SmmFvbFunctionHeader = (SMM_FVB_COMMUNICATE_FUNCTION_HEADER *) SmmCommunicateHeader->Data;
128 SmmFvbFunctionHeader->Function = Function;
129
130 *CommunicateBuffer = SmmCommunicateHeader;
131 *DataPtr = SmmFvbFunctionHeader->Data;
132
133 return EFI_SUCCESS;
134 }
135
136
137 /**
138 Send the data in communicate buffer to SMM.
139
140 @param[out] SmmCommunicateHeader The communicate buffer.
141 @param[in] DataSize The payload size.
142
143 **/
144 EFI_STATUS
145 SendCommunicateBuffer (
146 IN EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader,
147 IN UINTN DataSize
148 )
149 {
150 EFI_STATUS Status;
151 UINTN CommSize;
152 SMM_FVB_COMMUNICATE_FUNCTION_HEADER *SmmFvbFunctionHeader;
153
154 CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_FVB_COMMUNICATE_HEADER_SIZE;
155 Status = mSmmCommunication->Communicate (
156 mSmmCommunication,
157 SmmCommunicateHeader,
158 &CommSize
159 );
160 ASSERT_EFI_ERROR (Status);
161
162 SmmFvbFunctionHeader = (SMM_FVB_COMMUNICATE_FUNCTION_HEADER *) SmmCommunicateHeader->Data;
163 return SmmFvbFunctionHeader->ReturnStatus;
164 }
165
166 /**
167 This function retrieves the attributes and current settings of the block.
168
169 @param[in] This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
170
171 @param[out] Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the attributes
172 and current settings are returned. Type EFI_FVB_ATTRIBUTES_2
173 is defined in EFI_FIRMWARE_VOLUME_HEADER.
174
175 @retval EFI_SUCCESS The firmware volume attributes were returned.
176 @retval EFI_INVALID_PARAMETER Attributes is NULL.
177 **/
178 EFI_STATUS
179 EFIAPI
180 FvbGetAttributes (
181 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
182 OUT EFI_FVB_ATTRIBUTES_2 *Attributes
183 )
184 {
185 EFI_STATUS Status;
186 UINTN PayloadSize;
187 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
188 SMM_FVB_ATTRIBUTES_HEADER *SmmFvbAttributesHeader;
189 EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;
190 EFI_FVB_DEVICE *FvbDevice;
191
192 if (Attributes == NULL) {
193 return EFI_INVALID_PARAMETER;
194 }
195
196 FvbDevice = FVB_DEVICE_FROM_THIS (This);
197 SmmFvb = FvbDevice->SmmFvbInstance;
198
199 //
200 // Initialize the communicate buffer.
201 //
202 PayloadSize = sizeof (SMM_FVB_ATTRIBUTES_HEADER);
203 Status = InitCommunicateBuffer (
204 (VOID **)&SmmCommunicateHeader,
205 (VOID **)&SmmFvbAttributesHeader,
206 PayloadSize,
207 EFI_FUNCTION_GET_ATTRIBUTES
208 );
209 if (EFI_ERROR (Status)) {
210 return Status;
211 }
212
213 SmmFvbAttributesHeader->SmmFvb = SmmFvb;
214 SmmFvbAttributesHeader->Attributes = 0;
215
216 //
217 // Send data to SMM.
218 //
219 Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
220
221 //
222 // Get data from SMM.
223 //
224 *Attributes = SmmFvbAttributesHeader->Attributes;
225 FreePool (SmmCommunicateHeader);
226
227 return Status;
228 }
229
230
231 /**
232 Sets Volume attributes. No polarity translations are done.
233
234 @param[in] This Calling context.
235 @param[out] Attributes Output buffer which contains attributes.
236
237 @retval EFI_SUCCESS Set the Attributes successfully.
238 @retval EFI_INVALID_PARAMETER Attributes is NULL.
239
240 **/
241 EFI_STATUS
242 EFIAPI
243 FvbSetAttributes (
244 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
245 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
246 )
247 {
248 EFI_STATUS Status;
249 UINTN PayloadSize;
250 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
251 SMM_FVB_ATTRIBUTES_HEADER *SmmFvbAttributesHeader;
252 EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;
253 EFI_FVB_DEVICE *FvbDevice;
254
255 if (Attributes == NULL) {
256 return EFI_INVALID_PARAMETER;
257 }
258
259 FvbDevice = FVB_DEVICE_FROM_THIS (This);
260 SmmFvb = FvbDevice->SmmFvbInstance;
261
262 //
263 // Initialize the communicate buffer.
264 //
265 PayloadSize = sizeof (SMM_FVB_ATTRIBUTES_HEADER);
266 Status = InitCommunicateBuffer (
267 (VOID **)&SmmCommunicateHeader,
268 (VOID **)&SmmFvbAttributesHeader,
269 PayloadSize,
270 EFI_FUNCTION_SET_ATTRIBUTES
271 );
272 if (EFI_ERROR (Status)) {
273 return Status;
274 }
275
276 SmmFvbAttributesHeader->SmmFvb = SmmFvb;
277 SmmFvbAttributesHeader->Attributes = *Attributes;
278
279 //
280 // Send data to SMM.
281 //
282 Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
283
284 //
285 // Get data from SMM.
286 //
287 *Attributes = SmmFvbAttributesHeader->Attributes;
288 FreePool (SmmCommunicateHeader);
289
290 return Status;
291 }
292
293
294 /**
295 Retrieves the physical address of the FVB instance.
296
297 @param[in] SmmFvb A pointer to EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL.
298 @param[out] Address Output buffer containing the address.
299
300 @retval EFI_SUCCESS Get the address successfully.
301 @retval Others Failed to get address.
302
303 **/
304 EFI_STATUS
305 GetPhysicalAddress (
306 IN EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb,
307 OUT EFI_PHYSICAL_ADDRESS *Address
308 )
309 {
310 EFI_STATUS Status;
311 UINTN PayloadSize;
312 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
313 SMM_FVB_PHYSICAL_ADDRESS_HEADER *SmmFvbPhysicalAddressHeader;
314
315 //
316 // Initialize the communicate buffer.
317 //
318 PayloadSize = sizeof (SMM_FVB_PHYSICAL_ADDRESS_HEADER);
319 Status = InitCommunicateBuffer (
320 (VOID **)&SmmCommunicateHeader,
321 (VOID **)&SmmFvbPhysicalAddressHeader,
322 PayloadSize,
323 EFI_FUNCTION_GET_PHYSICAL_ADDRESS
324 );
325 if (EFI_ERROR (Status)) {
326 return Status;
327 }
328
329 SmmFvbPhysicalAddressHeader->SmmFvb = SmmFvb;
330 SmmFvbPhysicalAddressHeader->Address = 0;
331
332 //
333 // Send data to SMM.
334 //
335 Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
336
337 //
338 // Get data from SMM.
339 //
340 *Address = SmmFvbPhysicalAddressHeader->Address;
341 FreePool (SmmCommunicateHeader);
342
343 return Status;
344 }
345
346
347 /**
348 Retrieves the physical address of the FVB instance.
349
350 @param[in] This A pointer to EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL.
351 @param[out] Address Output buffer containing the address.
352
353 @retval EFI_SUCCESS Get the address successfully.
354 @retval Others Failed to get the address.
355
356 **/
357 EFI_STATUS
358 EFIAPI
359 FvbGetPhysicalAddress (
360 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
361 OUT EFI_PHYSICAL_ADDRESS *Address
362 )
363 {
364 EFI_STATUS Status;
365 EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;
366 EFI_FVB_DEVICE *FvbDevice;
367
368 if (Address == NULL) {
369 return EFI_INVALID_PARAMETER;
370 }
371
372 FvbDevice = FVB_DEVICE_FROM_THIS (This);
373 SmmFvb = FvbDevice->SmmFvbInstance;
374
375 Status = GetPhysicalAddress (SmmFvb, Address);
376
377 return Status;
378 }
379
380
381 /**
382 Retrieve the size of a logical block.
383
384 @param[in] This Calling context.
385 @param[in] Lba Indicates which block to return the size for.
386 @param[out] BlockSize A pointer to a caller allocated UINTN in which
387 the size of the block is returned.
388 @param[out] NumOfBlocks A pointer to a caller allocated UINTN in which the
389 number of consecutive blocks starting with Lba is
390 returned. All blocks in this range have a size of
391 BlockSize.
392
393 @retval EFI_SUCCESS Get BlockSize and NumOfBlocks successfully.
394 @retval EFI_INVALID_PARAMETER BlockSize or NumOfBlocks are NULL.
395 **/
396 EFI_STATUS
397 EFIAPI
398 FvbGetBlockSize (
399 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
400 IN EFI_LBA Lba,
401 OUT UINTN *BlockSize,
402 OUT UINTN *NumOfBlocks
403 )
404 {
405 EFI_STATUS Status;
406 UINTN PayloadSize;
407 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
408 SMM_FVB_BLOCK_SIZE_HEADER *SmmFvbBlockSizeHeader;
409 EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;
410 EFI_FVB_DEVICE *FvbDevice;
411
412 if ((BlockSize == NULL) || (NumOfBlocks == NULL)) {
413 return EFI_INVALID_PARAMETER;
414 }
415
416 FvbDevice = FVB_DEVICE_FROM_THIS (This);
417 SmmFvb = FvbDevice->SmmFvbInstance;
418
419 //
420 // Initialize the communicate buffer.
421 //
422 PayloadSize = sizeof (SMM_FVB_BLOCK_SIZE_HEADER);
423 Status = InitCommunicateBuffer (
424 (VOID **)&SmmCommunicateHeader,
425 (VOID **)&SmmFvbBlockSizeHeader,
426 PayloadSize,
427 EFI_FUNCTION_GET_BLOCK_SIZE
428 );
429 if (EFI_ERROR (Status)) {
430 return Status;
431 }
432
433 SmmFvbBlockSizeHeader->SmmFvb = SmmFvb;
434 SmmFvbBlockSizeHeader->Lba = Lba;
435
436 //
437 // Send data to SMM.
438 //
439 Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
440
441 //
442 // Get data from SMM.
443 //
444 *BlockSize = SmmFvbBlockSizeHeader->BlockSize;
445 *NumOfBlocks = SmmFvbBlockSizeHeader->NumOfBlocks;
446 FreePool (SmmCommunicateHeader);
447
448 return Status;
449 }
450
451
452 /**
453 Reads data beginning at Lba:Offset from FV. The Read terminates either
454 when *NumBytes of data have been read, or when a block boundary is
455 reached. *NumBytes is updated to reflect the actual number of bytes
456 written. The write opertion does not include erase. This routine will
457 attempt to write only the specified bytes. If the writes do not stick,
458 it will return an error.
459
460 @param[in] This Calling context
461 @param[in] Lba Block in which to begin write
462 @param[in] Offset Offset in the block at which to begin write
463 @param[in,out] NumBytes On input, indicates the requested write size. On
464 output, indicates the actual number of bytes written
465 @param[in] Buffer Buffer containing source data for the write.
466
467 @retval EFI_SUCCESS The firmware volume was read successfully and
468 contents are in Buffer.
469 @retval EFI_BAD_BUFFER_SIZE Read attempted across a LBA boundary. On output,
470 NumBytes contains the total number of bytes returned
471 in Buffer.
472 @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state
473 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
474 could not be read.
475 @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL.
476
477 **/
478 EFI_STATUS
479 EFIAPI
480 FvbRead (
481 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
482 IN EFI_LBA Lba,
483 IN UINTN Offset,
484 IN OUT UINTN *NumBytes,
485 OUT UINT8 *Buffer
486 )
487 {
488 EFI_STATUS Status;
489 UINTN PayloadSize;
490 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
491 SMM_FVB_READ_WRITE_HEADER *SmmFvbReadWriteHeader;
492 EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;
493 EFI_FVB_DEVICE *FvbDevice;
494
495 if ((NumBytes == NULL) || (Buffer == NULL)) {
496 return EFI_INVALID_PARAMETER;
497 }
498
499 FvbDevice = FVB_DEVICE_FROM_THIS (This);
500 SmmFvb = FvbDevice->SmmFvbInstance;
501
502 //
503 // Initialize the communicate buffer.
504 //
505 PayloadSize = sizeof (SMM_FVB_READ_WRITE_HEADER) + *NumBytes;
506 Status = InitCommunicateBuffer (
507 (VOID **)&SmmCommunicateHeader,
508 (VOID **)&SmmFvbReadWriteHeader,
509 PayloadSize, EFI_FUNCTION_READ
510 );
511 if (EFI_ERROR (Status)) {
512 return Status;
513 }
514
515 SmmFvbReadWriteHeader->SmmFvb = SmmFvb;
516 SmmFvbReadWriteHeader->Lba = Lba;
517 SmmFvbReadWriteHeader->Offset = Offset;
518 SmmFvbReadWriteHeader->NumBytes = *NumBytes;
519
520 //
521 // Send data to SMM.
522 //
523 Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
524
525 //
526 // Get data from SMM.
527 //
528 *NumBytes = SmmFvbReadWriteHeader->NumBytes;
529 if (!EFI_ERROR (Status)) {
530 CopyMem (Buffer, (UINT8 *)(SmmFvbReadWriteHeader + 1), *NumBytes);
531 }
532 FreePool (SmmCommunicateHeader);
533
534 return Status;
535 }
536
537
538 /**
539 Writes data beginning at Lba:Offset from FV. The write terminates either
540 when *NumBytes of data have been written, or when a block boundary is
541 reached. *NumBytes is updated to reflect the actual number of bytes
542 written. The write opertion does not include erase. This routine will
543 attempt to write only the specified bytes. If the writes do not stick,
544 it will return an error.
545
546 @param[in] This Calling context.
547 @param[in] Lba Block in which to begin write.
548 @param[in] Offset Offset in the block at which to begin write.
549 @param[in,out] NumBytes On input, indicates the requested write size. On
550 output, indicates the actual number of bytes written.
551 @param[in] Buffer Buffer containing source data for the write.
552
553 @retval EFI_SUCCESS The firmware volume was written successfully.
554 @retval EFI_BAD_BUFFER_SIZE Write attempted across a LBA boundary. On output,
555 NumBytes contains the total number of bytes
556 actually written.
557 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.
558 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
559 could not be written.
560 @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL.
561
562 **/
563 EFI_STATUS
564 EFIAPI
565 FvbWrite (
566 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
567 IN EFI_LBA Lba,
568 IN UINTN Offset,
569 IN OUT UINTN *NumBytes,
570 IN UINT8 *Buffer
571 )
572 {
573 EFI_STATUS Status;
574 UINTN PayloadSize;
575 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
576 SMM_FVB_READ_WRITE_HEADER *SmmFvbReadWriteHeader;
577 EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;
578 EFI_FVB_DEVICE *FvbDevice;
579
580 if ((NumBytes == NULL) || (Buffer == NULL)) {
581 return EFI_INVALID_PARAMETER;
582 }
583
584 FvbDevice = FVB_DEVICE_FROM_THIS (This);
585 SmmFvb = FvbDevice->SmmFvbInstance;
586
587 //
588 // Initialize the communicate buffer.
589 //
590 PayloadSize = sizeof (SMM_FVB_READ_WRITE_HEADER) + *NumBytes;
591 Status = InitCommunicateBuffer (
592 (VOID **)&SmmCommunicateHeader,
593 (VOID **)&SmmFvbReadWriteHeader,
594 PayloadSize,
595 EFI_FUNCTION_WRITE
596 );
597 if (EFI_ERROR (Status)) {
598 return Status;
599 }
600
601 SmmFvbReadWriteHeader->SmmFvb = SmmFvb;
602 SmmFvbReadWriteHeader->Lba = Lba;
603 SmmFvbReadWriteHeader->Offset = Offset;
604 SmmFvbReadWriteHeader->NumBytes = *NumBytes;
605 CopyMem ((UINT8 *)(SmmFvbReadWriteHeader + 1), Buffer, *NumBytes);
606
607 //
608 // Send data to SMM.
609 //
610 Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
611
612 //
613 // Get data from SMM.
614 //
615 *NumBytes = SmmFvbReadWriteHeader->NumBytes;
616 FreePool (SmmCommunicateHeader);
617
618 return Status;
619 }
620
621
622 /**
623 The EraseBlock() function erases NumOfLba blocks started from StartingLba.
624
625 @param[in] This Calling context.
626 @param[in] StartingLba Starting LBA followed to erase.
627 @param[in] NumOfLba Number of block to erase.
628
629 @retval EFI_SUCCESS The erase request was successfully completed.
630 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.
631 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
632 could not be written. Firmware device may have been
633 partially erased.
634
635 **/
636 EFI_STATUS
637 EraseBlock (
638 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
639 IN EFI_LBA StartingLba,
640 IN UINTN NumOfLba
641 )
642 {
643 EFI_STATUS Status;
644 UINTN PayloadSize;
645 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
646 SMM_FVB_BLOCKS_HEADER *SmmFvbBlocksHeader;
647 EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;
648 EFI_FVB_DEVICE *FvbDevice;
649
650 FvbDevice = FVB_DEVICE_FROM_THIS (This);
651 SmmFvb = FvbDevice->SmmFvbInstance;
652
653 //
654 // Initialize the communicate buffer.
655 //
656 PayloadSize = sizeof (SMM_FVB_BLOCKS_HEADER);
657 Status = InitCommunicateBuffer (
658 (VOID **)&SmmCommunicateHeader,
659 (VOID **)&SmmFvbBlocksHeader,
660 PayloadSize,
661 EFI_FUNCTION_ERASE_BLOCKS
662 );
663 if (EFI_ERROR (Status)) {
664 return Status;
665 }
666
667 SmmFvbBlocksHeader->SmmFvb = SmmFvb;
668 SmmFvbBlocksHeader->StartLba = StartingLba;
669 SmmFvbBlocksHeader->NumOfLba = NumOfLba;
670
671 //
672 // Send data to SMM.
673 //
674 Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
675
676 //
677 // Get data from SMM.
678 //
679 FreePool (SmmCommunicateHeader);
680
681 return Status;
682 }
683
684
685 /**
686 The EraseBlocks() function erases one or more blocks as denoted by the
687 variable argument list. The entire parameter list of blocks must be verified
688 prior to erasing any blocks. If a block is requested that does not exist
689 within the associated firmware volume (it has a larger index than the last
690 block of the firmware volume), the EraseBlock() function must return
691 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
692
693 @param[in] This Calling context/
694 @param[in] ... Starting LBA followed by Number of Lba to erase.
695 a -1 to terminate the list.
696 /
697 @retval EFI_SUCCESS The erase request was successfully completed
698 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state/
699 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
700 could not be written. Firmware device may have been
701 partially erased/
702
703 **/
704 EFI_STATUS
705 EFIAPI
706 FvbEraseBlocks (
707 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
708 ...
709 )
710 {
711 EFI_STATUS Status;
712 VA_LIST Marker;
713 EFI_LBA StartingLba;
714 UINTN NumOfLba;
715
716 Status = EFI_SUCCESS;
717
718 //
719 // Check the parameter.
720 //
721 VA_START (Marker, This);
722 do {
723 StartingLba = VA_ARG (Marker, EFI_LBA);
724 if (StartingLba == EFI_LBA_LIST_TERMINATOR ) {
725 break;
726 }
727
728 NumOfLba = VA_ARG (Marker, UINT32);
729 if (NumOfLba == 0) {
730 return EFI_INVALID_PARAMETER;
731 }
732
733 } while ( 1 );
734 VA_END (Marker);
735
736 //
737 // Erase the blocks.
738 //
739 VA_START (Marker, This);
740 do {
741 StartingLba = VA_ARG (Marker, EFI_LBA);
742 if (StartingLba == EFI_LBA_LIST_TERMINATOR ) {
743 break;
744 }
745 NumOfLba = VA_ARG (Marker, UINT32);
746 Status = EraseBlock (This, StartingLba, NumOfLba);
747 if (EFI_ERROR (Status)) {
748 break;
749 }
750 } while ( 1 );
751 VA_END (Marker);
752
753 return Status;
754 }
755
756
757 /**
758 Install the FVB protocol which based on SMM FVB protocol.
759
760 @param[in] SmmFvb The SMM FVB protocol.
761
762 **/
763 VOID
764 InstallFvb (
765 IN EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb
766 )
767 {
768 EFI_STATUS Status;
769 EFI_HANDLE FvbHandle;
770 EFI_FVB_DEVICE *FvbDevice;
771 EFI_FIRMWARE_VOLUME_HEADER *VolumeHeader;
772 EFI_PHYSICAL_ADDRESS Address;
773 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFvbInterface;
774
775 FvbDevice = AllocateRuntimeCopyPool (sizeof (EFI_FVB_DEVICE), &mFvbDeviceTemplate);
776 ASSERT (FvbDevice != NULL);
777 FvbDevice->SmmFvbInstance = SmmFvb;
778
779 Status = gBS->LocateProtocol (
780 &gEfiSmmCommunicationProtocolGuid,
781 NULL,
782 (VOID **) &mSmmCommunication
783 );
784 ASSERT_EFI_ERROR (Status);
785
786 Status = GetPhysicalAddress (SmmFvb, &Address);
787 ASSERT_EFI_ERROR (Status);
788
789 VolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN)Address;
790
791 //
792 // Set up the devicepath.
793 //
794 if (VolumeHeader->ExtHeaderOffset == 0) {
795 //
796 // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH.
797 //
798 FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateRuntimeCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate);
799 ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.StartingAddress = (UINTN)Address;
800 ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.EndingAddress = (UINTN)Address + VolumeHeader->FvLength - 1;
801 } else {
802 FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateRuntimeCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate);
803 CopyGuid (
804 &((FV_PIWG_DEVICE_PATH *)FvbDevice->DevicePath)->FvDevPath.FvName,
805 (GUID *)(UINTN)((UINTN)Address + VolumeHeader->ExtHeaderOffset)
806 );
807 }
808
809 //
810 // Find a handle with a matching device path that has supports FW Block protocol.
811 //
812 Status = gBS->LocateDevicePath (
813 &gEfiFirmwareVolumeBlockProtocolGuid,
814 &FvbDevice->DevicePath,
815 &FvbHandle
816 );
817 if (EFI_ERROR (Status) ) {
818 //
819 // LocateDevicePath fails so install a new interface and device path.
820 //
821 FvbHandle = NULL;
822 Status = gBS->InstallMultipleProtocolInterfaces (
823 &FvbHandle,
824 &gEfiFirmwareVolumeBlockProtocolGuid,
825 &FvbDevice->FvbInstance,
826 &gEfiDevicePathProtocolGuid,
827 FvbDevice->DevicePath,
828 NULL
829 );
830 ASSERT_EFI_ERROR (Status);
831 } else if (IsDevicePathEnd (FvbDevice->DevicePath)) {
832 //
833 // Device allready exists, so reinstall the FVB protocol.
834 //
835 Status = gBS->HandleProtocol (
836 FvbHandle,
837 &gEfiFirmwareVolumeBlockProtocolGuid,
838 (VOID **) &OldFvbInterface
839 );
840 ASSERT_EFI_ERROR (Status);
841
842 Status = gBS->ReinstallProtocolInterface (
843 FvbHandle,
844 &gEfiFirmwareVolumeBlockProtocolGuid,
845 OldFvbInterface,
846 &FvbDevice->FvbInstance
847 );
848 ASSERT_EFI_ERROR (Status);
849 } else {
850 //
851 // There was a FVB protocol on an End Device Path node.
852 //
853 ASSERT (FALSE);
854 }
855 }
856
857
858 /**
859 SMM Firmware Volume Block Protocol notification event handler.
860
861 Discover NV Variable Store and install Variable Write Arch Protocol.
862
863 @param[in] Event Event whose notification function is being invoked.
864 @param[in] Context Pointer to the notification function's context.
865 **/
866 VOID
867 EFIAPI
868 SmmFvbReady (
869 IN EFI_EVENT Event,
870 IN VOID *Context
871 )
872 {
873 EFI_STATUS Status;
874 EFI_HANDLE *HandleBuffer;
875 UINTN HandleCount;
876 UINTN Index;
877 EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;
878
879 //
880 // Locate all handles of Smm Fvb protocol.
881 //
882 Status = gBS->LocateHandleBuffer (
883 ByProtocol,
884 &gEfiSmmFirmwareVolumeBlockProtocolGuid,
885 NULL,
886 &HandleCount,
887 &HandleBuffer
888 );
889 if (EFI_ERROR (Status)) {
890 return ;
891 }
892
893 //
894 // Install FVB protocol.
895 //
896 for (Index = 0; Index < HandleCount; Index++) {
897 SmmFvb = NULL;
898 Status = gBS->HandleProtocol (
899 HandleBuffer[Index],
900 &gEfiSmmFirmwareVolumeBlockProtocolGuid,
901 (VOID **) &SmmFvb
902 );
903 if (EFI_ERROR (Status)) {
904 break;
905 }
906
907 InstallFvb (SmmFvb);
908 }
909
910 FreePool (HandleBuffer);
911 }
912
913
914 /**
915 The driver entry point for Firmware Volume Block Driver.
916
917 The function does the necessary initialization work
918 Firmware Volume Block Driver.
919
920 @param[in] ImageHandle The firmware allocated handle for the UEFI image.
921 @param[in] SystemTable A pointer to the EFI system table.
922
923 @retval EFI_SUCCESS This funtion always return EFI_SUCCESS.
924 It will ASSERT on errors.
925
926 **/
927 EFI_STATUS
928 EFIAPI
929 FvbSmmDxeInitialize (
930 IN EFI_HANDLE ImageHandle,
931 IN EFI_SYSTEM_TABLE *SystemTable
932 )
933 {
934 VOID *SmmFvbRegistration;
935
936 //
937 // Smm FVB driver is ready.
938 //
939 EfiCreateProtocolNotifyEvent (
940 &gEfiSmmFirmwareVolumeBlockProtocolGuid,
941 TPL_CALLBACK,
942 SmmFvbReady,
943 NULL,
944 &SmmFvbRegistration
945 );
946
947 return EFI_SUCCESS;
948 }
949