1 /*++ 2 3 Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved. 4 5 This program and the accompanying materials are licensed and made available under 7 the terms and conditions of the BSD License that accompanies this distribution. 9 The full text of the license may be found at 11 http://opensource.org/licenses/bsd-license.php. 13 15 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 17 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 19 21 23 24 25 Module Name: 26 27 MiscOemType0x88Function.c 28 29 Abstract: 30 31 The function that processes the Smbios data type 0x88 before they 32 are submitted to Data Hub 33 34 --*/ 35 36 #include "CommonHeader.h" 37 38 #include "MiscSubclassDriver.h" 39 #include <Library/PrintLib.h> 40 #include <Library/CpuIA32.h> 41 #include <Protocol/DxeSmmReadyToLock.h> 42 43 44 VOID 45 GetCPUStepping ( ) 46 { 47 CHAR16 Buffer[40]; 48 49 UINT16 FamilyId; 50 UINT8 Model; 51 UINT8 SteppingId; 52 UINT8 ProcessorType; 53 54 55 EfiCpuVersion (&FamilyId, &Model, &SteppingId, &ProcessorType); 56 57 // 58 //we need raw Model data 59 // 60 Model = Model & 0xf; 61 62 // 63 //Family/Model/Step 64 // 65 UnicodeSPrint (Buffer, sizeof (Buffer), L"%d/%d/%d", FamilyId, Model, SteppingId); 66 HiiSetString(mHiiHandle,STRING_TOKEN(STR_MISC_PROCESSOR_STEPPING), Buffer, NULL); 67 68 } 69 70 EFI_STATUS 71 SearchChildHandle( 72 EFI_HANDLE Father, 73 EFI_HANDLE *Child 74 ) 75 { 76 EFI_STATUS Status; 77 UINTN HandleIndex; 78 EFI_GUID **ProtocolGuidArray = NULL; 79 UINTN ArrayCount; 80 UINTN ProtocolIndex; 81 UINTN OpenInfoCount; 82 UINTN OpenInfoIndex; 83 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo = NULL; 84 UINTN mHandleCount; 85 EFI_HANDLE *mHandleBuffer= NULL; 86 87 // 88 // Retrieve the list of all handles from the handle database 89 // 90 Status = gBS->LocateHandleBuffer ( 91 AllHandles, 92 NULL, 93 NULL, 94 &mHandleCount, 95 &mHandleBuffer 96 ); 97 98 for (HandleIndex = 0; HandleIndex < mHandleCount; HandleIndex++) { 99 // 100 // Retrieve the list of all the protocols on each handle 101 // 102 Status = gBS->ProtocolsPerHandle ( 103 mHandleBuffer[HandleIndex], 104 &ProtocolGuidArray, 105 &ArrayCount 106 ); 107 if (!EFI_ERROR (Status)) { 108 for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) { 109 Status = gBS->OpenProtocolInformation ( 110 mHandleBuffer[HandleIndex], 111 ProtocolGuidArray[ProtocolIndex], 112 &OpenInfo, 113 &OpenInfoCount 114 ); 115 116 if (!EFI_ERROR (Status)) { 117 for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) { 118 if(OpenInfo[OpenInfoIndex].AgentHandle == Father) { 119 if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) == EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) { 120 *Child = mHandleBuffer[HandleIndex]; 121 Status = EFI_SUCCESS; 122 goto TryReturn; 123 } 124 } 125 } 126 Status = EFI_NOT_FOUND; 127 } 128 } 129 if(OpenInfo != NULL) { 130 FreePool(OpenInfo); 131 OpenInfo = NULL; 132 } 133 } 134 if(ProtocolGuidArray != NULL) { 135 FreePool (ProtocolGuidArray); 136 ProtocolGuidArray = NULL; 137 } 138 } 139 TryReturn: 140 if(OpenInfo != NULL) { 141 FreePool (OpenInfo); 142 OpenInfo = NULL; 143 } 144 if(ProtocolGuidArray != NULL) { 145 FreePool(ProtocolGuidArray); 146 ProtocolGuidArray = NULL; 147 } 148 if(mHandleBuffer != NULL) { 149 FreePool (mHandleBuffer); 150 mHandleBuffer = NULL; 151 } 152 return Status; 153 } 154 155 EFI_STATUS 156 JudgeHandleIsPCIDevice( 157 EFI_HANDLE Handle, 158 UINT8 Device, 159 UINT8 Funs 160 ) 161 { 162 EFI_STATUS Status; 163 EFI_DEVICE_PATH *DPath; 164 165 Status = gBS->HandleProtocol ( 166 Handle, 167 &gEfiDevicePathProtocolGuid, 168 (VOID **) &DPath 169 ); 170 if(!EFI_ERROR(Status)) { 171 while(!IsDevicePathEnd(DPath)) { 172 if((DPath->Type == HARDWARE_DEVICE_PATH) && (DPath->SubType == HW_PCI_DP)) { 173 PCI_DEVICE_PATH *PCIPath; 174 PCIPath = (PCI_DEVICE_PATH*) DPath; 175 DPath = NextDevicePathNode(DPath); 176 177 if(IsDevicePathEnd(DPath) && (PCIPath->Device == Device) && (PCIPath->Function == Funs)) { 178 return EFI_SUCCESS; 179 } 180 } else { 181 DPath = NextDevicePathNode(DPath); 182 } 183 } 184 } 185 return EFI_UNSUPPORTED; 186 } 187 188 EFI_STATUS 189 GetDriverName( 190 EFI_HANDLE Handle 191 ) 192 { 193 EFI_DRIVER_BINDING_PROTOCOL *BindHandle = NULL; 194 EFI_STATUS Status; 195 UINT32 Version; 196 UINT16 *Ptr; 197 CHAR16 Buffer[40]; 198 STRING_REF TokenToUpdate; 199 Status = gBS->OpenProtocol( 200 Handle, 201 &gEfiDriverBindingProtocolGuid, 202 (VOID**)&BindHandle, 203 NULL, 204 NULL, 205 EFI_OPEN_PROTOCOL_GET_PROTOCOL 206 ); 207 208 if (EFI_ERROR(Status)) { 209 return EFI_NOT_FOUND; 210 } 211 212 Version = BindHandle->Version; 213 Ptr = (UINT16*)&Version; 214 UnicodeSPrint(Buffer, sizeof (Buffer), L"%d.%d.%d", Version >> 24 , (Version >>16)& 0x0f ,*(Ptr)); 215 216 TokenToUpdate = (STRING_REF)STR_MISC_GOP_VERSION; 217 HiiSetString(mHiiHandle, TokenToUpdate, Buffer, NULL); 218 219 return EFI_SUCCESS; 220 } 221 222 EFI_STATUS 223 GetGOPDriverName() 224 { 225 UINTN HandleCount; 226 EFI_HANDLE *Handles= NULL; 227 UINTN Index; 228 EFI_STATUS Status; 229 EFI_HANDLE Child = 0; 230 231 Status = gBS->LocateHandleBuffer( 232 ByProtocol, 233 &gEfiDriverBindingProtocolGuid, 234 NULL, 235 &HandleCount, 236 &Handles 237 ); 238 239 for (Index = 0; Index < HandleCount ; Index++) { 240 Status = SearchChildHandle(Handles[Index], &Child); 241 if(!EFI_ERROR(Status)) { 242 Status = JudgeHandleIsPCIDevice(Child, 0x02, 0x00); 243 if(!EFI_ERROR(Status)) { 244 return GetDriverName(Handles[Index]); 245 } 246 } 247 } 248 return EFI_UNSUPPORTED; 249 } 250 251 VOID 252 GetUcodeVersion() 253 { 254 UINT32 MicroCodeVersion; 255 CHAR16 Buffer[40]; 256 257 // 258 // Microcode Revision 259 // 260 EfiWriteMsr (EFI_MSR_IA32_BIOS_SIGN_ID, 0); 261 EfiCpuid (EFI_CPUID_VERSION_INFO, NULL); 262 MicroCodeVersion = (UINT32) RShiftU64 (EfiReadMsr (EFI_MSR_IA32_BIOS_SIGN_ID), 32); 263 UnicodeSPrint (Buffer, sizeof (Buffer), L"%x", MicroCodeVersion); 264 HiiSetString(mHiiHandle,STRING_TOKEN(STR_MISC_UCODE_VERSION), Buffer, NULL); 265 } 266 267 /** 268 Publish the smbios OEM type 0x90. 269 270 @param Event - Event whose notification function is being invoked (gEfiDxeSmmReadyToLockProtocolGuid). 271 @param Context - Pointer to the notification functions context, which is implementation dependent. 272 273 @retval None 274 275 **/ 276 EFI_STATUS 277 EFIAPI 278 AddSmbiosT0x90Callback ( 279 IN EFI_EVENT Event, 280 IN VOID *Context 281 ) 282 { 283 EFI_STATUS Status; 284 UINTN SECVerStrLen = 0; 285 UINTN uCodeVerStrLen = 0; 286 UINTN GOPStrLen = 0; 287 UINTN SteppingStrLen = 0; 288 SMBIOS_TABLE_TYPE90 *SmbiosRecord; 289 EFI_SMBIOS_HANDLE SmbiosHandle; 290 CHAR16 *SECVer; 291 CHAR16 *uCodeVer; 292 CHAR16 *GOPVer; 293 CHAR16 *Stepping; 294 STRING_REF TokenToGet; 295 CHAR8 *OptionalStrStart; 296 EFI_SMBIOS_PROTOCOL *SmbiosProtocol; 297 298 DEBUG ((EFI_D_INFO, "Executing SMBIOS T0x90 callback.\n")); 299 300 gBS->CloseEvent (Event); // Unload this event. 301 302 // 303 // First check for invalid parameters. 304 // 305 if (Context == NULL) { 306 return EFI_INVALID_PARAMETER; 307 } 308 309 Status = gBS->LocateProtocol ( 310 &gEfiSmbiosProtocolGuid, 311 NULL, 312 (VOID *) &SmbiosProtocol 313 ); 314 ASSERT_EFI_ERROR (Status); 315 316 GetUcodeVersion(); 317 GetGOPDriverName(); 318 GetCPUStepping(); 319 320 TokenToGet = STRING_TOKEN (STR_MISC_SEC_VERSION); 321 SECVer = SmbiosMiscGetString (TokenToGet); 322 SECVerStrLen = StrLen(SECVer); 323 if (SECVerStrLen > SMBIOS_STRING_MAX_LENGTH) { 324 return EFI_UNSUPPORTED; 325 } 326 327 TokenToGet = STRING_TOKEN (STR_MISC_UCODE_VERSION); 328 uCodeVer = SmbiosMiscGetString (TokenToGet); 329 uCodeVerStrLen = StrLen(uCodeVer); 330 if (uCodeVerStrLen > SMBIOS_STRING_MAX_LENGTH) { 331 return EFI_UNSUPPORTED; 332 } 333 334 TokenToGet = STRING_TOKEN (STR_MISC_GOP_VERSION); 335 GOPVer = SmbiosMiscGetString (TokenToGet); 336 GOPStrLen = StrLen(GOPVer); 337 if (GOPStrLen > SMBIOS_STRING_MAX_LENGTH) { 338 return EFI_UNSUPPORTED; 339 } 340 341 TokenToGet = STRING_TOKEN (STR_MISC_PROCESSOR_STEPPING); 342 Stepping = SmbiosMiscGetString (TokenToGet); 343 SteppingStrLen = StrLen(Stepping); 344 345 346 if (SteppingStrLen > SMBIOS_STRING_MAX_LENGTH) { 347 return EFI_UNSUPPORTED; 348 } 349 350 SmbiosRecord = AllocatePool(sizeof (SMBIOS_TABLE_TYPE90) + SECVerStrLen + 1 + uCodeVerStrLen + 1 + GOPStrLen + 1 + SteppingStrLen + 1 + 1); 351 ZeroMem(SmbiosRecord, sizeof (SMBIOS_TABLE_TYPE90) + SECVerStrLen + 1 + uCodeVerStrLen + 1 + GOPStrLen + 1 + SteppingStrLen + 1 + 1); 352 353 SmbiosRecord->Hdr.Type = EFI_SMBIOS_TYPE_FIRMWARE_VERSION_INFO; 354 SmbiosRecord->Hdr.Length = sizeof (SMBIOS_TABLE_TYPE90); 355 356 // 357 // Make handle chosen by smbios protocol.add automatically. 358 // 359 SmbiosRecord->Hdr.Handle = 0; 360 361 // 362 // SEC VERSION will be the 1st optional string following the formatted structure. 363 // 364 SmbiosRecord->SECVersion = 0; 365 366 // 367 // Microcode VERSION will be the 2nd optional string following the formatted structure. 368 // 369 SmbiosRecord->uCodeVersion = 2; 370 371 // 372 // GOP VERSION will be the 3rd optional string following the formatted structure. 373 // 374 SmbiosRecord->GOPVersion = 3; 375 376 // 377 // CPU Stepping will be the 4th optional string following the formatted structure. 378 // 379 SmbiosRecord->CpuStepping = 4; 380 381 OptionalStrStart = (CHAR8 *)(SmbiosRecord + 1); 382 UnicodeStrToAsciiStr(SECVer, OptionalStrStart); 383 UnicodeStrToAsciiStr(uCodeVer, OptionalStrStart + SECVerStrLen + 1); 384 UnicodeStrToAsciiStr(GOPVer, OptionalStrStart + SECVerStrLen + 1 + uCodeVerStrLen + 1); 385 UnicodeStrToAsciiStr(Stepping, OptionalStrStart + SECVerStrLen + 1 + uCodeVerStrLen + 1 + GOPStrLen + 1); 386 387 // 388 // Now we have got the full smbios record, call smbios protocol to add this record. 389 // 390 SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED; 391 Status = SmbiosProtocol-> Add( 392 SmbiosProtocol, 393 NULL, 394 &SmbiosHandle, 395 (EFI_SMBIOS_TABLE_HEADER *) SmbiosRecord 396 ); 397 398 FreePool(SmbiosRecord); 399 return Status; 400 } 401 402 403 /** 404 This function makes boot time changes to the contents of the 405 MiscOemType0x90 (Type 0x90). 406 407 @param RecordData Pointer to copy of RecordData from the Data Table. 408 409 @retval EFI_SUCCESS All parameters were valid. 410 @retval EFI_UNSUPPORTED Unexpected RecordType value. 411 @retval EFI_INVALID_PARAMETER Invalid parameter was found. 412 413 **/ 414 MISC_SMBIOS_TABLE_FUNCTION(MiscOemType0x90) 415 { 416 EFI_STATUS Status; 417 static BOOLEAN CallbackIsInstalledT0x90 = FALSE; 418 VOID *AddSmbiosT0x90CallbackNotifyReg; 419 EFI_EVENT AddSmbiosT0x90CallbackEvent; 420 421 // 422 // This callback will create a OEM Type 0x90 record. 423 // 424 if (CallbackIsInstalledT0x90 == FALSE) { 425 CallbackIsInstalledT0x90 = TRUE; // Prevent more than 1 callback. 426 DEBUG ((EFI_D_INFO, "Create Smbios T0x90 callback.\n")); 427 428 // 429 // gEfiDxeSmmReadyToLockProtocolGuid is ready 430 // 431 Status = gBS->CreateEvent ( 432 EVT_NOTIFY_SIGNAL, 433 TPL_CALLBACK, 434 (EFI_EVENT_NOTIFY)AddSmbiosT0x90Callback, 435 RecordData, 436 &AddSmbiosT0x90CallbackEvent 437 ); 438 439 ASSERT_EFI_ERROR (Status); 440 if (EFI_ERROR (Status)) { 441 return Status; 442 443 } 444 445 Status = gBS->RegisterProtocolNotify ( 446 &gEfiDxeSmmReadyToLockProtocolGuid, 447 AddSmbiosT0x90CallbackEvent, 448 &AddSmbiosT0x90CallbackNotifyReg 449 ); 450 451 return Status; 452 } 453 454 return EFI_SUCCESS; 455 456 } 457