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