| 1 | /** @file\r |
| 2 | If the Variable services have PcdVariableCollectStatistics set to TRUE then\r |
| 3 | this utility will print out the statistics information. You can use console\r |
| 4 | redirection to capture the data.\r |
| 5 | \r |
| 6 | Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>\r |
| 7 | SPDX-License-Identifier: BSD-2-Clause-Patent\r |
| 8 | \r |
| 9 | **/\r |
| 10 | \r |
| 11 | #include <Uefi.h>\r |
| 12 | #include <Library/UefiLib.h>\r |
| 13 | #include <Library/UefiApplicationEntryPoint.h>\r |
| 14 | #include <Library/BaseMemoryLib.h>\r |
| 15 | #include <Library/BaseLib.h>\r |
| 16 | #include <Library/MemoryAllocationLib.h>\r |
| 17 | #include <Library/DebugLib.h>\r |
| 18 | #include <Library/UefiBootServicesTableLib.h>\r |
| 19 | \r |
| 20 | #include <Guid/VariableFormat.h>\r |
| 21 | #include <Guid/SmmVariableCommon.h>\r |
| 22 | #include <Guid/PiSmmCommunicationRegionTable.h>\r |
| 23 | #include <Protocol/SmmCommunication.h>\r |
| 24 | #include <Protocol/SmmVariable.h>\r |
| 25 | \r |
| 26 | EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;\r |
| 27 | \r |
| 28 | /**\r |
| 29 | This function get the variable statistics data from SMM variable driver.\r |
| 30 | \r |
| 31 | @param[in, out] SmmCommunicateHeader In input, a pointer to a collection of data that will\r |
| 32 | be passed into an SMM environment. In output, a pointer\r |
| 33 | to a collection of data that comes from an SMM environment.\r |
| 34 | @param[in, out] SmmCommunicateSize The size of the SmmCommunicateHeader.\r |
| 35 | \r |
| 36 | @retval EFI_SUCCESS Get the statistics data information.\r |
| 37 | @retval EFI_NOT_FOUND Not found.\r |
| 38 | @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r |
| 39 | \r |
| 40 | **/\r |
| 41 | EFI_STATUS\r |
| 42 | EFIAPI\r |
| 43 | GetVariableStatisticsData (\r |
| 44 | IN OUT EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader,\r |
| 45 | IN OUT UINTN *SmmCommunicateSize\r |
| 46 | )\r |
| 47 | {\r |
| 48 | EFI_STATUS Status;\r |
| 49 | SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;\r |
| 50 | \r |
| 51 | CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r |
| 52 | SmmCommunicateHeader->MessageLength = *SmmCommunicateSize - OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);\r |
| 53 | \r |
| 54 | SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) &SmmCommunicateHeader->Data[0];\r |
| 55 | SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_STATISTICS;\r |
| 56 | \r |
| 57 | Status = mSmmCommunication->Communicate (mSmmCommunication, SmmCommunicateHeader, SmmCommunicateSize);\r |
| 58 | ASSERT_EFI_ERROR (Status);\r |
| 59 | \r |
| 60 | Status = SmmVariableFunctionHeader->ReturnStatus;\r |
| 61 | return Status;\r |
| 62 | }\r |
| 63 | \r |
| 64 | /**\r |
| 65 | \r |
| 66 | This function get and print the variable statistics data from SMM variable driver.\r |
| 67 | \r |
| 68 | @retval EFI_SUCCESS Print the statistics information successfully.\r |
| 69 | @retval EFI_NOT_FOUND Not found the statistics information.\r |
| 70 | \r |
| 71 | **/\r |
| 72 | EFI_STATUS\r |
| 73 | PrintInfoFromSmm (\r |
| 74 | VOID\r |
| 75 | )\r |
| 76 | {\r |
| 77 | EFI_STATUS Status;\r |
| 78 | VARIABLE_INFO_ENTRY *VariableInfo;\r |
| 79 | EFI_SMM_COMMUNICATE_HEADER *CommBuffer;\r |
| 80 | UINTN RealCommSize;\r |
| 81 | UINTN CommSize;\r |
| 82 | SMM_VARIABLE_COMMUNICATE_HEADER *FunctionHeader;\r |
| 83 | EFI_SMM_VARIABLE_PROTOCOL *Smmvariable;\r |
| 84 | EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *PiSmmCommunicationRegionTable;\r |
| 85 | UINT32 Index;\r |
| 86 | EFI_MEMORY_DESCRIPTOR *Entry;\r |
| 87 | UINTN Size;\r |
| 88 | UINTN MaxSize;\r |
| 89 | \r |
| 90 | Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **) &Smmvariable);\r |
| 91 | if (EFI_ERROR (Status)) {\r |
| 92 | return Status;\r |
| 93 | }\r |
| 94 | \r |
| 95 | Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);\r |
| 96 | if (EFI_ERROR (Status)) {\r |
| 97 | return Status;\r |
| 98 | }\r |
| 99 | \r |
| 100 | CommBuffer = NULL;\r |
| 101 | RealCommSize = 0;\r |
| 102 | Status = EfiGetSystemConfigurationTable (\r |
| 103 | &gEdkiiPiSmmCommunicationRegionTableGuid,\r |
| 104 | (VOID **) &PiSmmCommunicationRegionTable\r |
| 105 | );\r |
| 106 | if (EFI_ERROR (Status)) {\r |
| 107 | return Status;\r |
| 108 | }\r |
| 109 | ASSERT (PiSmmCommunicationRegionTable != NULL);\r |
| 110 | Entry = (EFI_MEMORY_DESCRIPTOR *) (PiSmmCommunicationRegionTable + 1);\r |
| 111 | Size = 0;\r |
| 112 | MaxSize = 0;\r |
| 113 | for (Index = 0; Index < PiSmmCommunicationRegionTable->NumberOfEntries; Index++) {\r |
| 114 | if (Entry->Type == EfiConventionalMemory) {\r |
| 115 | Size = EFI_PAGES_TO_SIZE ((UINTN) Entry->NumberOfPages);\r |
| 116 | if (Size > (SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (VARIABLE_INFO_ENTRY))) {\r |
| 117 | if (Size > MaxSize) {\r |
| 118 | MaxSize = Size;\r |
| 119 | RealCommSize = MaxSize;\r |
| 120 | CommBuffer = (EFI_SMM_COMMUNICATE_HEADER *) (UINTN) Entry->PhysicalStart;\r |
| 121 | }\r |
| 122 | }\r |
| 123 | }\r |
| 124 | Entry = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) Entry + PiSmmCommunicationRegionTable->DescriptorSize);\r |
| 125 | }\r |
| 126 | ASSERT (CommBuffer != NULL);\r |
| 127 | ZeroMem (CommBuffer, RealCommSize);\r |
| 128 | \r |
| 129 | Print (L"Non-Volatile SMM Variables:\n");\r |
| 130 | do {\r |
| 131 | CommSize = RealCommSize;\r |
| 132 | Status = GetVariableStatisticsData (CommBuffer, &CommSize);\r |
| 133 | if (Status == EFI_BUFFER_TOO_SMALL) {\r |
| 134 | Print (L"The generic SMM communication buffer provided by SmmCommunicationRegionTable is too small\n");\r |
| 135 | return Status;\r |
| 136 | }\r |
| 137 | \r |
| 138 | if (EFI_ERROR (Status) || (CommSize <= SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE)) {\r |
| 139 | break;\r |
| 140 | }\r |
| 141 | \r |
| 142 | FunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) CommBuffer->Data;\r |
| 143 | VariableInfo = (VARIABLE_INFO_ENTRY *) FunctionHeader->Data;\r |
| 144 | \r |
| 145 | if (!VariableInfo->Volatile) {\r |
| 146 | Print (\r |
| 147 | L"%g R%03d(%03d) W%03d D%03d:%s\n",\r |
| 148 | &VariableInfo->VendorGuid,\r |
| 149 | VariableInfo->ReadCount,\r |
| 150 | VariableInfo->CacheCount,\r |
| 151 | VariableInfo->WriteCount,\r |
| 152 | VariableInfo->DeleteCount,\r |
| 153 | (CHAR16 *)(VariableInfo + 1)\r |
| 154 | );\r |
| 155 | }\r |
| 156 | } while (TRUE);\r |
| 157 | \r |
| 158 | Print (L"Volatile SMM Variables:\n");\r |
| 159 | ZeroMem (CommBuffer, RealCommSize);\r |
| 160 | do {\r |
| 161 | CommSize = RealCommSize;\r |
| 162 | Status = GetVariableStatisticsData (CommBuffer, &CommSize);\r |
| 163 | if (Status == EFI_BUFFER_TOO_SMALL) {\r |
| 164 | Print (L"The generic SMM communication buffer provided by SmmCommunicationRegionTable is too small\n");\r |
| 165 | return Status;\r |
| 166 | }\r |
| 167 | \r |
| 168 | if (EFI_ERROR (Status) || (CommSize <= SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE)) {\r |
| 169 | break;\r |
| 170 | }\r |
| 171 | \r |
| 172 | FunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) CommBuffer->Data;\r |
| 173 | VariableInfo = (VARIABLE_INFO_ENTRY *) FunctionHeader->Data;\r |
| 174 | \r |
| 175 | if (VariableInfo->Volatile) {\r |
| 176 | Print (\r |
| 177 | L"%g R%03d(%03d) W%03d D%03d:%s\n",\r |
| 178 | &VariableInfo->VendorGuid,\r |
| 179 | VariableInfo->ReadCount,\r |
| 180 | VariableInfo->CacheCount,\r |
| 181 | VariableInfo->WriteCount,\r |
| 182 | VariableInfo->DeleteCount,\r |
| 183 | (CHAR16 *)(VariableInfo + 1)\r |
| 184 | );\r |
| 185 | }\r |
| 186 | } while (TRUE);\r |
| 187 | \r |
| 188 | return Status;\r |
| 189 | }\r |
| 190 | \r |
| 191 | /**\r |
| 192 | The user Entry Point for Application. The user code starts with this function\r |
| 193 | as the real entry point for the image goes into a library that calls this\r |
| 194 | function.\r |
| 195 | \r |
| 196 | @param[in] ImageHandle The firmware allocated handle for the EFI image.\r |
| 197 | @param[in] SystemTable A pointer to the EFI System Table.\r |
| 198 | \r |
| 199 | @retval EFI_SUCCESS The entry point is executed successfully.\r |
| 200 | @retval other Some error occurs when executing this entry point.\r |
| 201 | \r |
| 202 | **/\r |
| 203 | EFI_STATUS\r |
| 204 | EFIAPI\r |
| 205 | UefiMain (\r |
| 206 | IN EFI_HANDLE ImageHandle,\r |
| 207 | IN EFI_SYSTEM_TABLE *SystemTable\r |
| 208 | )\r |
| 209 | {\r |
| 210 | EFI_STATUS Status;\r |
| 211 | VARIABLE_INFO_ENTRY *VariableInfo;\r |
| 212 | VARIABLE_INFO_ENTRY *Entry;\r |
| 213 | \r |
| 214 | Status = EfiGetSystemConfigurationTable (&gEfiVariableGuid, (VOID **)&Entry);\r |
| 215 | if (EFI_ERROR (Status) || (Entry == NULL)) {\r |
| 216 | Status = EfiGetSystemConfigurationTable (&gEfiAuthenticatedVariableGuid, (VOID **)&Entry);\r |
| 217 | }\r |
| 218 | \r |
| 219 | if (EFI_ERROR (Status) || (Entry == NULL)) {\r |
| 220 | Status = PrintInfoFromSmm ();\r |
| 221 | if (!EFI_ERROR (Status)) {\r |
| 222 | return Status;\r |
| 223 | }\r |
| 224 | }\r |
| 225 | \r |
| 226 | if (!EFI_ERROR (Status) && (Entry != NULL)) {\r |
| 227 | Print (L"Non-Volatile EFI Variables:\n");\r |
| 228 | VariableInfo = Entry;\r |
| 229 | do {\r |
| 230 | if (!VariableInfo->Volatile) {\r |
| 231 | Print (\r |
| 232 | L"%g R%03d(%03d) W%03d D%03d:%s\n",\r |
| 233 | &VariableInfo->VendorGuid,\r |
| 234 | VariableInfo->ReadCount,\r |
| 235 | VariableInfo->CacheCount,\r |
| 236 | VariableInfo->WriteCount,\r |
| 237 | VariableInfo->DeleteCount,\r |
| 238 | VariableInfo->Name\r |
| 239 | );\r |
| 240 | }\r |
| 241 | \r |
| 242 | VariableInfo = VariableInfo->Next;\r |
| 243 | } while (VariableInfo != NULL);\r |
| 244 | \r |
| 245 | Print (L"Volatile EFI Variables:\n");\r |
| 246 | VariableInfo = Entry;\r |
| 247 | do {\r |
| 248 | if (VariableInfo->Volatile) {\r |
| 249 | Print (\r |
| 250 | L"%g R%03d(%03d) W%03d D%03d:%s\n",\r |
| 251 | &VariableInfo->VendorGuid,\r |
| 252 | VariableInfo->ReadCount,\r |
| 253 | VariableInfo->CacheCount,\r |
| 254 | VariableInfo->WriteCount,\r |
| 255 | VariableInfo->DeleteCount,\r |
| 256 | VariableInfo->Name\r |
| 257 | );\r |
| 258 | }\r |
| 259 | VariableInfo = VariableInfo->Next;\r |
| 260 | } while (VariableInfo != NULL);\r |
| 261 | \r |
| 262 | } else {\r |
| 263 | Print (L"Warning: Variable Dxe/Smm driver doesn't enable the feature of statistical information!\n");\r |
| 264 | Print (L"If you want to see this info, please:\n");\r |
| 265 | Print (L" 1. Set PcdVariableCollectStatistics as TRUE\n");\r |
| 266 | Print (L" 2. Rebuild Variable Dxe/Smm driver\n");\r |
| 267 | Print (L" 3. Run \"VariableInfo\" cmd again\n");\r |
| 268 | }\r |
| 269 | \r |
| 270 | return Status;\r |
| 271 | }\r |