1 /*++ 2 3 Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR> 4 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 13 Module Name: 14 15 SmmRuntimeDxeSupport.c 16 17 Abstract: 18 19 Report Status Code Library for DXE Phase. 20 21 --*/ 22 23 #include "ReportStatusCodeLibInternal.h" 24 #include EFI_PROTOCOL_DEFINITION (SmmStatusCode) 25 26 EFI_EVENT mVirtualAddressChangeEvent; 27 28 EFI_EVENT mExitBootServicesEvent; 29 30 EFI_STATUS_CODE_DATA *mStatusCodeData; 31 32 BOOLEAN mInSmm; 33 34 EFI_SMM_BASE_PROTOCOL *mSmmBase; 35 36 EFI_RUNTIME_SERVICES *mRTSmmRuntimeDxeReportStatusCodeLib; 37 38 BOOLEAN mHaveExitedBootServices = FALSE; 39 40 EFI_SMM_STATUS_CODE_PROTOCOL *mSmmStatusCode; 41 42 VOID 43 SmmStatusCodeInitialize ( 44 VOID 45 ) 46 { 47 EFI_STATUS Status; 48 49 Status = gBS->LocateProtocol (&gEfiSmmStatusCodeProtocolGuid, NULL, (VOID **) &mSmmStatusCode); 50 if (EFI_ERROR (Status)) { 51 mSmmStatusCode = NULL; 52 } 53 } 54 55 EFI_STATUS 56 SmmStatusCodeReport ( 57 IN EFI_STATUS_CODE_TYPE Type, 58 IN EFI_STATUS_CODE_VALUE Value, 59 IN UINT32 Instance, 60 IN EFI_GUID *CallerId OPTIONAL, 61 IN EFI_STATUS_CODE_DATA *Data OPTIONAL 62 ) 63 { 64 if (mSmmStatusCode != NULL) { 65 (mSmmStatusCode->ReportStatusCode) (mSmmStatusCode, Type, Value, Instance, CallerId, Data); 66 } 67 return EFI_SUCCESS; 68 } 69 70 /** 71 Locate he report status code service. 72 73 @return EFI_REPORT_STATUS_CODE function point to 74 ReportStatusCode. 75 **/ 76 EFI_REPORT_STATUS_CODE 77 InternalGetReportStatusCode ( 78 VOID 79 ) 80 { 81 #if (EFI_SPECIFICATION_VERSION >= 0x00020000) 82 EFI_STATUS_CODE_PROTOCOL *StatusCodeProtocol; 83 EFI_STATUS Status; 84 #endif 85 86 if (mInSmm) { 87 return (EFI_REPORT_STATUS_CODE) SmmStatusCodeReport; 88 #if (EFI_SPECIFICATION_VERSION >= 0x00020000) 89 } else if (!mHaveExitedBootServices) { 90 // 91 // Check gBS just in case. ReportStatusCode is called before gBS is initialized. 92 // 93 if (gBS != NULL) { 94 Status = gBS->LocateProtocol (&gEfiStatusCodeRuntimeProtocolGuid, NULL, (VOID**)&StatusCodeProtocol); 95 if (!EFI_ERROR (Status) && StatusCodeProtocol != NULL) { 96 return StatusCodeProtocol->ReportStatusCode; 97 } 98 } 99 } 100 #elif (TIANO_RELEASE_VERSION != 0) 101 } else if (mRTSmmRuntimeDxeReportStatusCodeLib != NULL) { 102 return mRTSmmRuntimeDxeReportStatusCodeLib->ReportStatusCode; 103 } 104 #endif 105 106 return NULL; 107 } 108 109 110 /** 111 Fixup internal report status code protocol interface. 112 113 @param[in] Event The Event that is being processed 114 @param[in] Context Event Context 115 **/ 116 VOID 117 EFIAPI 118 ReportStatusCodeLibVirtualAddressChange ( 119 IN EFI_EVENT Event, 120 IN VOID *Context 121 ) 122 { 123 if (NULL != mReportStatusCode) { 124 mRTSmmRuntimeDxeReportStatusCodeLib->ConvertPointer (0, (VOID **) &mReportStatusCode); 125 } 126 mRTSmmRuntimeDxeReportStatusCodeLib->ConvertPointer (0, (VOID **) &mStatusCodeData); 127 mRTSmmRuntimeDxeReportStatusCodeLib->ConvertPointer (0, (VOID **) &mRTSmmRuntimeDxeReportStatusCodeLib); 128 } 129 130 /** 131 Update the In Runtime Indicator. 132 133 @param[in] Event The Event that is being processed 134 @param[in] Context Event Context 135 **/ 136 VOID 137 EFIAPI 138 ReportStatusCodeLibExitBootServices ( 139 IN EFI_EVENT Event, 140 IN VOID *Context 141 ) 142 { 143 // 144 // If mReportStatusCode is NULL, then see if a Status Code Protocol instance is present 145 // in the handle database. 146 // 147 if (mReportStatusCode == NULL) { 148 mReportStatusCode = InternalGetReportStatusCode (); 149 } 150 151 mHaveExitedBootServices = TRUE; 152 } 153 154 /** 155 Intialize Report Status Code Lib. 156 157 @param[in] ImageHandle The firmware allocated handle for the EFI image. 158 @param[in] SystemTable A pointer to the EFI System Table. 159 160 @return EFI_STATUS always returns EFI_SUCCESS. 161 **/ 162 EFI_STATUS 163 EFIAPI 164 ReportStatusCodeLibConstruct ( 165 IN EFI_HANDLE ImageHandle, 166 IN EFI_SYSTEM_TABLE *SystemTable 167 ) 168 { 169 EFI_STATUS Status; 170 171 // 172 // SMM driver depends on the SMM BASE protocol. 173 // the SMM driver must be success to locate protocol. 174 // 175 Status = gBS->LocateProtocol (&gEfiSmmBaseProtocolGuid, NULL, (VOID **) &mSmmBase); 176 if (!EFI_ERROR (Status)) { 177 mSmmBase->InSmm (mSmmBase, &mInSmm); 178 if (mInSmm) { 179 Status = mSmmBase->SmmAllocatePool ( 180 mSmmBase, 181 EfiRuntimeServicesData, 182 sizeof (EFI_STATUS_CODE_DATA) + EFI_STATUS_CODE_DATA_MAX_SIZE, 183 (VOID **) &mStatusCodeData 184 ); 185 ASSERT_EFI_ERROR (Status); 186 SmmStatusCodeInitialize (); 187 return EFI_SUCCESS; 188 } 189 } 190 191 // 192 // Library should not use the gRT directly, since it 193 // may be converted by other library instance. 194 // 195 mRTSmmRuntimeDxeReportStatusCodeLib = gRT; 196 mInSmm = FALSE; 197 198 (gBS->AllocatePool) (EfiRuntimeServicesData, sizeof (EFI_STATUS_CODE_DATA) + EFI_STATUS_CODE_DATA_MAX_SIZE, (VOID **)&mStatusCodeData); 199 ASSERT (NULL != mStatusCodeData); 200 // 201 // Cache the report status code service 202 // 203 mReportStatusCode = InternalGetReportStatusCode (); 204 205 // 206 // Register the call back of virtual address change 207 // 208 Status = gBS->CreateEvent ( 209 EFI_EVENT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, 210 TPL_NOTIFY, 211 ReportStatusCodeLibVirtualAddressChange, 212 NULL, 213 &mVirtualAddressChangeEvent 214 ); 215 ASSERT_EFI_ERROR (Status); 216 217 218 // 219 // Register the call back of exit boot services 220 // 221 Status = gBS->CreateEvent ( 222 EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES, 223 TPL_NOTIFY, 224 ReportStatusCodeLibExitBootServices, 225 NULL, 226 &mExitBootServicesEvent 227 ); 228 ASSERT_EFI_ERROR (Status); 229 230 return Status; 231 } 232 233 /** 234 Desctructor of library will close events. 235 236 @param ImageHandle callder module's image handle 237 @param SystemTable pointer to EFI system table. 238 @return the status of close event. 239 **/ 240 EFI_STATUS 241 EFIAPI 242 ReportStatusCodeLibDestruct ( 243 IN EFI_HANDLE ImageHandle, 244 IN EFI_SYSTEM_TABLE *SystemTable 245 ) 246 { 247 EFI_STATUS Status; 248 249 if (!mInSmm) { 250 // 251 // Close SetVirtualAddressMap () notify function 252 // 253 ASSERT (gBS != NULL); 254 Status = gBS->CloseEvent (mVirtualAddressChangeEvent); 255 ASSERT_EFI_ERROR (Status); 256 Status = gBS->CloseEvent (mExitBootServicesEvent); 257 ASSERT_EFI_ERROR (Status); 258 259 (gBS->FreePool) (mStatusCodeData); 260 } else { 261 mSmmBase->SmmFreePool (mSmmBase, mStatusCodeData); 262 } 263 264 return EFI_SUCCESS; 265 } 266 267 /** 268 Reports a status code with full parameters. 269 270 The function reports a status code. If ExtendedData is NULL and ExtendedDataSize 271 is 0, then an extended data buffer is not reported. If ExtendedData is not 272 NULL and ExtendedDataSize is not 0, then an extended data buffer is allocated. 273 ExtendedData is assumed not have the standard status code header, so this function 274 is responsible for allocating a buffer large enough for the standard header and 275 the extended data passed into this function. The standard header is filled in 276 with a GUID specified by ExtendedDataGuid. If ExtendedDataGuid is NULL, then a 277 GUID of gEfiStatusCodeSpecificDatauid is used. The status code is reported with 278 an instance specified by Instance and a caller ID specified by CallerId. If 279 CallerId is NULL, then a caller ID of gEfiCallerIdGuid is used. 280 281 ReportStatusCodeEx()must actively prevent recursion. If ReportStatusCodeEx() 282 is called while processing another any other Report Status Code Library function, 283 then ReportStatusCodeEx() must return EFI_DEVICE_ERROR immediately. 284 285 If ExtendedData is NULL and ExtendedDataSize is not zero, then ASSERT(). 286 If ExtendedData is not NULL and ExtendedDataSize is zero, then ASSERT(). 287 288 @param Type Status code type. 289 @param Value Status code value. 290 @param Instance Status code instance number. 291 @param CallerId Pointer to a GUID that identifies the caller of this 292 function. If this parameter is NULL, then a caller 293 ID of gEfiCallerIdGuid is used. 294 @param ExtendedDataGuid Pointer to the GUID for the extended data buffer. 295 If this parameter is NULL, then a the status code 296 standard header is filled in with 297 gEfiStatusCodeSpecificDataGuid. 298 @param ExtendedData Pointer to the extended data buffer. This is an 299 optional parameter that may be NULL. 300 @param ExtendedDataSize The size, in bytes, of the extended data buffer. 301 302 @retval EFI_SUCCESS The status code was reported. 303 @retval EFI_OUT_OF_RESOURCES There were not enough resources to allocate 304 the extended data section if it was specified. 305 @retval EFI_UNSUPPORTED Report status code is not supported 306 307 **/ 308 EFI_STATUS 309 EFIAPI 310 InternalReportStatusCodeEx ( 311 IN EFI_STATUS_CODE_TYPE Type, 312 IN EFI_STATUS_CODE_VALUE Value, 313 IN UINT32 Instance, 314 IN CONST EFI_GUID *CallerId OPTIONAL, 315 IN CONST EFI_GUID *ExtendedDataGuid OPTIONAL, 316 IN CONST VOID *ExtendedData OPTIONAL, 317 IN UINTN ExtendedDataSize 318 ) 319 { 320 ASSERT (!((ExtendedData == NULL) && (ExtendedDataSize != 0))); 321 ASSERT (!((ExtendedData != NULL) && (ExtendedDataSize == 0))); 322 323 if (ExtendedDataSize > EFI_STATUS_CODE_DATA_MAX_SIZE) { 324 return EFI_OUT_OF_RESOURCES; 325 } 326 327 // 328 // Fill in the extended data header 329 // 330 mStatusCodeData->HeaderSize = (UINT16) sizeof (EFI_STATUS_CODE_DATA); 331 mStatusCodeData->Size = (UINT16)ExtendedDataSize; 332 if (ExtendedDataGuid == NULL) { 333 ExtendedDataGuid = &gEfiStatusCodeSpecificDataGuid; 334 } 335 CopyGuid (&mStatusCodeData->Type, ExtendedDataGuid); 336 337 // 338 // Fill in the extended data buffer 339 // 340 CopyMem (mStatusCodeData + 1, ExtendedData, ExtendedDataSize); 341 342 // 343 // Report the status code 344 // 345 if (CallerId == NULL) { 346 CallerId = &gEfiCallerIdGuid; 347 } 348 return InternalReportStatusCode (Type, Value, Instance, CallerId, mStatusCodeData); 349 } 350 351