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