Vishal Bhoj | 82c8071 | 2015-12-15 21:13:33 +0530 | [diff] [blame] | 1 | /** @file
|
| 2 | This code produces the Smbios protocol. It also responsible for constructing
|
| 3 | SMBIOS table into system table.
|
| 4 |
|
| 5 | Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
|
| 6 | This program and the accompanying materials
|
| 7 | are licensed and made available under the terms and conditions of the BSD License
|
| 8 | which accompanies this distribution. The full text of the license may be found at
|
| 9 | http://opensource.org/licenses/bsd-license.php
|
| 10 |
|
| 11 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
| 12 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
| 13 |
|
| 14 | **/
|
| 15 |
|
| 16 | #include "SmbiosDxe.h"
|
| 17 |
|
| 18 | //
|
| 19 | // Module Global:
|
| 20 | // Since this driver will only ever produce one instance of the
|
| 21 | // protocol you are not required to dynamically allocate the PrivateData.
|
| 22 | //
|
| 23 | SMBIOS_INSTANCE mPrivateData;
|
| 24 |
|
| 25 | UINTN mPreAllocatedPages = 0;
|
| 26 |
|
| 27 | //
|
| 28 | // Chassis for SMBIOS entry point structure that is to be installed into EFI system config table.
|
| 29 | //
|
| 30 | SMBIOS_TABLE_ENTRY_POINT *EntryPointStructure = NULL;
|
| 31 | SMBIOS_TABLE_ENTRY_POINT EntryPointStructureData = {
|
| 32 | //
|
| 33 | // AnchorString
|
| 34 | //
|
| 35 | {
|
| 36 | 0x5f,
|
| 37 | 0x53,
|
| 38 | 0x4d,
|
| 39 | 0x5f
|
| 40 | },
|
| 41 | //
|
| 42 | // EntryPointStructureChecksum,TO BE FILLED
|
| 43 | //
|
| 44 | 0,
|
| 45 | //
|
| 46 | // EntryPointStructure Length
|
| 47 | //
|
| 48 | 0x1f,
|
| 49 | //
|
| 50 | // MajorVersion
|
| 51 | //
|
| 52 | 0,
|
| 53 | //
|
| 54 | // MinorVersion
|
| 55 | //
|
| 56 | 0,
|
| 57 | //
|
| 58 | // MaxStructureSize, TO BE FILLED
|
| 59 | //
|
| 60 | 0,
|
| 61 | //
|
| 62 | // EntryPointRevision
|
| 63 | //
|
| 64 | 0,
|
| 65 | //
|
| 66 | // FormattedArea
|
| 67 | //
|
| 68 | {
|
| 69 | 0,
|
| 70 | 0,
|
| 71 | 0,
|
| 72 | 0,
|
| 73 | 0
|
| 74 | },
|
| 75 | //
|
| 76 | // IntermediateAnchorString
|
| 77 | //
|
| 78 | {
|
| 79 | 0x5f,
|
| 80 | 0x44,
|
| 81 | 0x4d,
|
| 82 | 0x49,
|
| 83 | 0x5f
|
| 84 | },
|
| 85 | //
|
| 86 | // IntermediateChecksum, TO BE FILLED
|
| 87 | //
|
| 88 | 0,
|
| 89 | //
|
| 90 | // TableLength, TO BE FILLED
|
| 91 | //
|
| 92 | 0,
|
| 93 | //
|
| 94 | // TableAddress, TO BE FILLED
|
| 95 | //
|
| 96 | 0,
|
| 97 | //
|
| 98 | // NumberOfSmbiosStructures, TO BE FILLED
|
| 99 | //
|
| 100 | 0,
|
| 101 | //
|
| 102 | // SmbiosBcdRevision
|
| 103 | //
|
| 104 | 0
|
| 105 | };
|
| 106 |
|
| 107 |
|
| 108 |
|
| 109 | /**
|
| 110 |
|
| 111 | Get the full size of SMBIOS structure including optional strings that follow the formatted structure.
|
| 112 |
|
| 113 | @param This The EFI_SMBIOS_PROTOCOL instance.
|
| 114 | @param Head Pointer to the beginning of SMBIOS structure.
|
| 115 | @param Size The returned size.
|
| 116 | @param NumberOfStrings The returned number of optional strings that follow the formatted structure.
|
| 117 |
|
| 118 | @retval EFI_SUCCESS Size retured in Size.
|
| 119 | @retval EFI_INVALID_PARAMETER Input SMBIOS structure mal-formed or Size is NULL.
|
| 120 |
|
| 121 | **/
|
| 122 | EFI_STATUS
|
| 123 | EFIAPI
|
| 124 | GetSmbiosStructureSize (
|
| 125 | IN CONST EFI_SMBIOS_PROTOCOL *This,
|
| 126 | IN EFI_SMBIOS_TABLE_HEADER *Head,
|
| 127 | OUT UINTN *Size,
|
| 128 | OUT UINTN *NumberOfStrings
|
| 129 | )
|
| 130 | {
|
| 131 | UINTN FullSize;
|
| 132 | UINTN StrLen;
|
| 133 | UINTN MaxLen;
|
| 134 | INT8* CharInStr;
|
| 135 |
|
| 136 | if (Size == NULL || NumberOfStrings == NULL) {
|
| 137 | return EFI_INVALID_PARAMETER;
|
| 138 | }
|
| 139 |
|
| 140 | FullSize = Head->Length;
|
| 141 | CharInStr = (INT8*)Head + Head->Length;
|
| 142 | *Size = FullSize;
|
| 143 | *NumberOfStrings = 0;
|
| 144 | StrLen = 0;
|
| 145 | //
|
| 146 | // look for the two consecutive zeros, check the string limit by the way.
|
| 147 | //
|
| 148 | while (*CharInStr != 0 || *(CharInStr+1) != 0) {
|
| 149 | if (*CharInStr == 0) {
|
| 150 | *Size += 1;
|
| 151 | CharInStr++;
|
| 152 | }
|
| 153 |
|
| 154 | if (This->MajorVersion < 2 || (This->MajorVersion == 2 && This->MinorVersion < 7)){
|
| 155 | MaxLen = SMBIOS_STRING_MAX_LENGTH;
|
| 156 | } else {
|
| 157 | //
|
| 158 | // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string.
|
| 159 | // However, the length of the entire structure table (including all strings) must be reported
|
| 160 | // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,
|
| 161 | // which is a WORD field limited to 65,535 bytes.
|
| 162 | //
|
| 163 | MaxLen = SMBIOS_TABLE_MAX_LENGTH;
|
| 164 | }
|
| 165 |
|
| 166 | for (StrLen = 0 ; StrLen < MaxLen; StrLen++) {
|
| 167 | if (*(CharInStr+StrLen) == 0) {
|
| 168 | break;
|
| 169 | }
|
| 170 | }
|
| 171 |
|
| 172 | if (StrLen == MaxLen) {
|
| 173 | return EFI_INVALID_PARAMETER;
|
| 174 | }
|
| 175 |
|
| 176 | //
|
| 177 | // forward the pointer
|
| 178 | //
|
| 179 | CharInStr += StrLen;
|
| 180 | *Size += StrLen;
|
| 181 | *NumberOfStrings += 1;
|
| 182 | }
|
| 183 |
|
| 184 | //
|
| 185 | // count ending two zeros.
|
| 186 | //
|
| 187 | *Size += 2;
|
| 188 | return EFI_SUCCESS;
|
| 189 | }
|
| 190 |
|
| 191 | /**
|
| 192 |
|
| 193 | Determin whether an SmbiosHandle has already in use.
|
| 194 |
|
| 195 | @param Head Pointer to the beginning of SMBIOS structure.
|
| 196 | @param Handle A unique handle will be assigned to the SMBIOS record.
|
| 197 |
|
| 198 | @retval TRUE Smbios handle already in use.
|
| 199 | @retval FALSE Smbios handle is NOT used.
|
| 200 |
|
| 201 | **/
|
| 202 | BOOLEAN
|
| 203 | EFIAPI
|
| 204 | CheckSmbiosHandleExistance (
|
| 205 | IN LIST_ENTRY *Head,
|
| 206 | IN EFI_SMBIOS_HANDLE Handle
|
| 207 | )
|
| 208 | {
|
| 209 | LIST_ENTRY *Link;
|
| 210 | SMBIOS_HANDLE_ENTRY *HandleEntry;
|
| 211 |
|
| 212 | for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
|
| 213 | HandleEntry = SMBIOS_HANDLE_ENTRY_FROM_LINK(Link);
|
| 214 | if (HandleEntry->SmbiosHandle == Handle) {
|
| 215 | return TRUE;
|
| 216 | }
|
| 217 | }
|
| 218 |
|
| 219 | return FALSE;
|
| 220 | }
|
| 221 |
|
| 222 | /**
|
| 223 |
|
| 224 | Get the max SmbiosHandle that could be use.
|
| 225 |
|
| 226 | @param This The EFI_SMBIOS_PROTOCOL instance.
|
| 227 | @param MaxHandle The max handle that could be assigned to the SMBIOS record.
|
| 228 |
|
| 229 | **/
|
| 230 | VOID
|
| 231 | EFIAPI
|
| 232 | GetMaxSmbiosHandle (
|
| 233 | IN CONST EFI_SMBIOS_PROTOCOL *This,
|
| 234 | IN OUT EFI_SMBIOS_HANDLE *MaxHandle
|
| 235 | )
|
| 236 | {
|
| 237 | if (This->MajorVersion == 2 && This->MinorVersion == 0) {
|
| 238 | *MaxHandle = 0xFFFE;
|
| 239 | } else {
|
| 240 | *MaxHandle = 0xFEFF;
|
| 241 | }
|
| 242 | }
|
| 243 |
|
| 244 | /**
|
| 245 |
|
| 246 | Get an SmbiosHandle that could use.
|
| 247 |
|
| 248 | @param This The EFI_SMBIOS_PROTOCOL instance.
|
| 249 | @param SmbiosHandle A unique handle will be assigned to the SMBIOS record.
|
| 250 |
|
| 251 | @retval EFI_SUCCESS Smbios handle got.
|
| 252 | @retval EFI_OUT_OF_RESOURCES Smbios handle is NOT available.
|
| 253 |
|
| 254 | **/
|
| 255 | EFI_STATUS
|
| 256 | EFIAPI
|
| 257 | GetAvailableSmbiosHandle (
|
| 258 | IN CONST EFI_SMBIOS_PROTOCOL *This,
|
| 259 | IN OUT EFI_SMBIOS_HANDLE *Handle
|
| 260 | )
|
| 261 | {
|
| 262 | LIST_ENTRY *Head;
|
| 263 | SMBIOS_INSTANCE *Private;
|
| 264 | EFI_SMBIOS_HANDLE MaxSmbiosHandle;
|
| 265 | EFI_SMBIOS_HANDLE AvailableHandle;
|
| 266 |
|
| 267 | GetMaxSmbiosHandle(This, &MaxSmbiosHandle);
|
| 268 |
|
| 269 | Private = SMBIOS_INSTANCE_FROM_THIS (This);
|
| 270 | Head = &Private->AllocatedHandleListHead;
|
| 271 | for (AvailableHandle = 0; AvailableHandle < MaxSmbiosHandle; AvailableHandle++) {
|
| 272 | if (!CheckSmbiosHandleExistance(Head, AvailableHandle)) {
|
| 273 | *Handle = AvailableHandle;
|
| 274 | return EFI_SUCCESS;
|
| 275 | }
|
| 276 | }
|
| 277 |
|
| 278 | return EFI_OUT_OF_RESOURCES;
|
| 279 | }
|
| 280 |
|
| 281 |
|
| 282 | /**
|
| 283 | Add an SMBIOS record.
|
| 284 |
|
| 285 | @param This The EFI_SMBIOS_PROTOCOL instance.
|
| 286 | @param ProducerHandle The handle of the controller or driver associated with the SMBIOS information. NULL
|
| 287 | means no handle.
|
| 288 | @param SmbiosHandle On entry, the handle of the SMBIOS record to add. If FFFEh, then a unique handle
|
| 289 | will be assigned to the SMBIOS record. If the SMBIOS handle is already in use,
|
| 290 | EFI_ALREADY_STARTED is returned and the SMBIOS record is not updated.
|
| 291 | @param Record The data for the fixed portion of the SMBIOS record. The format of the record is
|
| 292 | determined by EFI_SMBIOS_TABLE_HEADER.Type. The size of the formatted area is defined
|
| 293 | by EFI_SMBIOS_TABLE_HEADER.Length and either followed by a double-null (0x0000) or
|
| 294 | a set of null terminated strings and a null.
|
| 295 |
|
| 296 | @retval EFI_SUCCESS Record was added.
|
| 297 | @retval EFI_OUT_OF_RESOURCES Record was not added due to lack of system resources.
|
| 298 | @retval EFI_ALREADY_STARTED The SmbiosHandle passed in was already in use.
|
| 299 |
|
| 300 | **/
|
| 301 | EFI_STATUS
|
| 302 | EFIAPI
|
| 303 | SmbiosAdd (
|
| 304 | IN CONST EFI_SMBIOS_PROTOCOL *This,
|
| 305 | IN EFI_HANDLE ProducerHandle, OPTIONAL
|
| 306 | IN OUT EFI_SMBIOS_HANDLE *SmbiosHandle,
|
| 307 | IN EFI_SMBIOS_TABLE_HEADER *Record
|
| 308 | )
|
| 309 | {
|
| 310 | VOID *Raw;
|
| 311 | UINTN TotalSize;
|
| 312 | UINTN RecordSize;
|
| 313 | UINTN StructureSize;
|
| 314 | UINTN NumberOfStrings;
|
| 315 | EFI_STATUS Status;
|
| 316 | LIST_ENTRY *Head;
|
| 317 | SMBIOS_INSTANCE *Private;
|
| 318 | EFI_SMBIOS_ENTRY *SmbiosEntry;
|
| 319 | EFI_SMBIOS_HANDLE MaxSmbiosHandle;
|
| 320 | SMBIOS_HANDLE_ENTRY *HandleEntry;
|
| 321 | EFI_SMBIOS_RECORD_HEADER *InternalRecord;
|
| 322 |
|
| 323 | if (SmbiosHandle == NULL) {
|
| 324 | return EFI_INVALID_PARAMETER;
|
| 325 | }
|
| 326 |
|
| 327 | Private = SMBIOS_INSTANCE_FROM_THIS (This);
|
| 328 | //
|
| 329 | // Check whether SmbiosHandle is already in use
|
| 330 | //
|
| 331 | Head = &Private->AllocatedHandleListHead;
|
| 332 | if (*SmbiosHandle != SMBIOS_HANDLE_PI_RESERVED && CheckSmbiosHandleExistance(Head, *SmbiosHandle)) {
|
| 333 | return EFI_ALREADY_STARTED;
|
| 334 | }
|
| 335 |
|
| 336 | //
|
| 337 | // when SmbiosHandle is 0xFFFE, an available handle will be assigned
|
| 338 | //
|
| 339 | if (*SmbiosHandle == SMBIOS_HANDLE_PI_RESERVED) {
|
| 340 | Status = GetAvailableSmbiosHandle(This, SmbiosHandle);
|
| 341 | if (EFI_ERROR(Status)) {
|
| 342 | return Status;
|
| 343 | }
|
| 344 | } else {
|
| 345 | //
|
| 346 | // Check this handle validity
|
| 347 | //
|
| 348 | GetMaxSmbiosHandle(This, &MaxSmbiosHandle);
|
| 349 | if (*SmbiosHandle > MaxSmbiosHandle) {
|
| 350 | return EFI_INVALID_PARAMETER;
|
| 351 | }
|
| 352 | }
|
| 353 |
|
| 354 | //
|
| 355 | // Calculate record size and string number
|
| 356 | //
|
| 357 | Status = GetSmbiosStructureSize(This, Record, &StructureSize, &NumberOfStrings);
|
| 358 | if (EFI_ERROR(Status)) {
|
| 359 | return Status;
|
| 360 | }
|
| 361 |
|
| 362 | if (EntryPointStructure->TableLength + StructureSize > SMBIOS_TABLE_MAX_LENGTH) {
|
| 363 | //
|
| 364 | // The length of the entire structure table (including all strings) must be reported
|
| 365 | // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,
|
| 366 | // which is a WORD field limited to 65,535 bytes.
|
| 367 | //
|
| 368 | return EFI_OUT_OF_RESOURCES;
|
| 369 | }
|
| 370 |
|
| 371 | //
|
| 372 | // Enter into critical section
|
| 373 | //
|
| 374 | Status = EfiAcquireLockOrFail (&Private->DataLock);
|
| 375 | if (EFI_ERROR (Status)) {
|
| 376 | return Status;
|
| 377 | }
|
| 378 |
|
| 379 | RecordSize = sizeof (EFI_SMBIOS_RECORD_HEADER) + StructureSize;
|
| 380 | TotalSize = sizeof (EFI_SMBIOS_ENTRY) + RecordSize;
|
| 381 |
|
| 382 | //
|
| 383 | // Allocate internal buffer
|
| 384 | //
|
| 385 | SmbiosEntry = AllocateZeroPool (TotalSize);
|
| 386 | if (SmbiosEntry == NULL) {
|
| 387 | EfiReleaseLock (&Private->DataLock);
|
| 388 | return EFI_OUT_OF_RESOURCES;
|
| 389 | }
|
| 390 | HandleEntry = AllocateZeroPool (sizeof(SMBIOS_HANDLE_ENTRY));
|
| 391 | if (HandleEntry == NULL) {
|
| 392 | EfiReleaseLock (&Private->DataLock);
|
| 393 | return EFI_OUT_OF_RESOURCES;
|
| 394 | }
|
| 395 |
|
| 396 | //
|
| 397 | // Build Handle Entry and insert into linked list
|
| 398 | //
|
| 399 | HandleEntry->Signature = SMBIOS_HANDLE_ENTRY_SIGNATURE;
|
| 400 | HandleEntry->SmbiosHandle = *SmbiosHandle;
|
| 401 | InsertTailList(&Private->AllocatedHandleListHead, &HandleEntry->Link);
|
| 402 |
|
| 403 | InternalRecord = (EFI_SMBIOS_RECORD_HEADER *) (SmbiosEntry + 1);
|
| 404 | Raw = (VOID *) (InternalRecord + 1);
|
| 405 |
|
| 406 | //
|
| 407 | // Build internal record Header
|
| 408 | //
|
| 409 | InternalRecord->Version = EFI_SMBIOS_RECORD_HEADER_VERSION;
|
| 410 | InternalRecord->HeaderSize = (UINT16) sizeof (EFI_SMBIOS_RECORD_HEADER);
|
| 411 | InternalRecord->RecordSize = RecordSize;
|
| 412 | InternalRecord->ProducerHandle = ProducerHandle;
|
| 413 | InternalRecord->NumberOfStrings = NumberOfStrings;
|
| 414 | //
|
| 415 | // Insert record into the internal linked list
|
| 416 | //
|
| 417 | SmbiosEntry->Signature = EFI_SMBIOS_ENTRY_SIGNATURE;
|
| 418 | SmbiosEntry->RecordHeader = InternalRecord;
|
| 419 | SmbiosEntry->RecordSize = TotalSize;
|
| 420 | InsertTailList (&Private->DataListHead, &SmbiosEntry->Link);
|
| 421 |
|
| 422 | CopyMem (Raw, Record, StructureSize);
|
| 423 | ((EFI_SMBIOS_TABLE_HEADER*)Raw)->Handle = *SmbiosHandle;
|
| 424 |
|
| 425 | //
|
| 426 | // Some UEFI drivers (such as network) need some information in SMBIOS table.
|
| 427 | // Here we create SMBIOS table and publish it in
|
| 428 | // configuration table, so other UEFI drivers can get SMBIOS table from
|
| 429 | // configuration table without depending on PI SMBIOS protocol.
|
| 430 | //
|
| 431 | SmbiosTableConstruction ();
|
| 432 |
|
| 433 | //
|
| 434 | // Leave critical section
|
| 435 | //
|
| 436 | EfiReleaseLock (&Private->DataLock);
|
| 437 | return EFI_SUCCESS;
|
| 438 | }
|
| 439 |
|
| 440 | /**
|
| 441 | Update the string associated with an existing SMBIOS record.
|
| 442 |
|
| 443 | @param This The EFI_SMBIOS_PROTOCOL instance.
|
| 444 | @param SmbiosHandle SMBIOS Handle of structure that will have its string updated.
|
| 445 | @param StringNumber The non-zero string number of the string to update
|
| 446 | @param String Update the StringNumber string with String.
|
| 447 |
|
| 448 | @retval EFI_SUCCESS SmbiosHandle had its StringNumber String updated.
|
| 449 | @retval EFI_INVALID_PARAMETER SmbiosHandle does not exist.
|
| 450 | @retval EFI_UNSUPPORTED String was not added because it is longer than the SMBIOS Table supports.
|
| 451 | @retval EFI_NOT_FOUND The StringNumber.is not valid for this SMBIOS record.
|
| 452 |
|
| 453 | **/
|
| 454 | EFI_STATUS
|
| 455 | EFIAPI
|
| 456 | SmbiosUpdateString (
|
| 457 | IN CONST EFI_SMBIOS_PROTOCOL *This,
|
| 458 | IN EFI_SMBIOS_HANDLE *SmbiosHandle,
|
| 459 | IN UINTN *StringNumber,
|
| 460 | IN CHAR8 *String
|
| 461 | )
|
| 462 | {
|
| 463 | UINTN InputStrLen;
|
| 464 | UINTN TargetStrLen;
|
| 465 | UINTN StrIndex;
|
| 466 | UINTN TargetStrOffset;
|
| 467 | UINTN NewEntrySize;
|
| 468 | CHAR8 *StrStart;
|
| 469 | VOID *Raw;
|
| 470 | LIST_ENTRY *Link;
|
| 471 | LIST_ENTRY *Head;
|
| 472 | EFI_STATUS Status;
|
| 473 | SMBIOS_INSTANCE *Private;
|
| 474 | EFI_SMBIOS_ENTRY *SmbiosEntry;
|
| 475 | EFI_SMBIOS_ENTRY *ResizedSmbiosEntry;
|
| 476 | EFI_SMBIOS_HANDLE MaxSmbiosHandle;
|
| 477 | EFI_SMBIOS_TABLE_HEADER *Record;
|
| 478 | EFI_SMBIOS_RECORD_HEADER *InternalRecord;
|
| 479 |
|
| 480 | //
|
| 481 | // Check args validity
|
| 482 | //
|
| 483 | GetMaxSmbiosHandle(This, &MaxSmbiosHandle);
|
| 484 |
|
| 485 | if (*SmbiosHandle > MaxSmbiosHandle) {
|
| 486 | return EFI_INVALID_PARAMETER;
|
| 487 | }
|
| 488 |
|
| 489 | if (String == NULL) {
|
| 490 | return EFI_ABORTED;
|
| 491 | }
|
| 492 |
|
| 493 | if (*StringNumber == 0) {
|
| 494 | return EFI_NOT_FOUND;
|
| 495 | }
|
| 496 |
|
| 497 | InputStrLen = AsciiStrLen(String);
|
| 498 |
|
| 499 | if (This->MajorVersion < 2 || (This->MajorVersion == 2 && This->MinorVersion < 7)) {
|
| 500 | if (InputStrLen > SMBIOS_STRING_MAX_LENGTH) {
|
| 501 | return EFI_UNSUPPORTED;
|
| 502 | }
|
| 503 | } else {
|
| 504 | //
|
| 505 | // Reference SMBIOS 2.7, chapter 6.1.3, it will have no limit on the length of each individual text string.
|
| 506 | // However, the length of the entire structure table (including all strings) must be reported
|
| 507 | // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,
|
| 508 | // which is a WORD field limited to 65,535 bytes.
|
| 509 | //
|
| 510 | if (InputStrLen > SMBIOS_TABLE_MAX_LENGTH) {
|
| 511 | return EFI_UNSUPPORTED;
|
| 512 | }
|
| 513 | }
|
| 514 |
|
| 515 | Private = SMBIOS_INSTANCE_FROM_THIS (This);
|
| 516 | //
|
| 517 | // Enter into critical section
|
| 518 | //
|
| 519 | Status = EfiAcquireLockOrFail (&Private->DataLock);
|
| 520 | if (EFI_ERROR (Status)) {
|
| 521 | return Status;
|
| 522 | }
|
| 523 |
|
| 524 | Head = &Private->DataListHead;
|
| 525 | for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
|
| 526 | SmbiosEntry = SMBIOS_ENTRY_FROM_LINK(Link);
|
| 527 | Record = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);
|
| 528 |
|
| 529 | if (Record->Handle == *SmbiosHandle) {
|
| 530 | //
|
| 531 | // Find out the specified SMBIOS record
|
| 532 | //
|
| 533 | if (*StringNumber > SmbiosEntry->RecordHeader->NumberOfStrings) {
|
| 534 | EfiReleaseLock (&Private->DataLock);
|
| 535 | return EFI_NOT_FOUND;
|
| 536 | }
|
| 537 | //
|
| 538 | // Point to unformed string section
|
| 539 | //
|
| 540 | StrStart = (CHAR8 *) Record + Record->Length;
|
| 541 |
|
| 542 | for (StrIndex = 1, TargetStrOffset = 0; StrIndex < *StringNumber; StrStart++, TargetStrOffset++) {
|
| 543 | //
|
| 544 | // A string ends in 00h
|
| 545 | //
|
| 546 | if (*StrStart == 0) {
|
| 547 | StrIndex++;
|
| 548 | }
|
| 549 |
|
| 550 | //
|
| 551 | // String section ends in double-null (0000h)
|
| 552 | //
|
| 553 | if (*StrStart == 0 && *(StrStart + 1) == 0) {
|
| 554 | EfiReleaseLock (&Private->DataLock);
|
| 555 | return EFI_NOT_FOUND;
|
| 556 | }
|
| 557 | }
|
| 558 |
|
| 559 | if (*StrStart == 0) {
|
| 560 | StrStart++;
|
| 561 | TargetStrOffset++;
|
| 562 | }
|
| 563 |
|
| 564 | //
|
| 565 | // Now we get the string target
|
| 566 | //
|
| 567 | TargetStrLen = AsciiStrLen(StrStart);
|
| 568 | if (InputStrLen == TargetStrLen) {
|
| 569 | AsciiStrCpy(StrStart, String);
|
| 570 | //
|
| 571 | // Some UEFI drivers (such as network) need some information in SMBIOS table.
|
| 572 | // Here we create SMBIOS table and publish it in
|
| 573 | // configuration table, so other UEFI drivers can get SMBIOS table from
|
| 574 | // configuration table without depending on PI SMBIOS protocol.
|
| 575 | //
|
| 576 | SmbiosTableConstruction ();
|
| 577 | EfiReleaseLock (&Private->DataLock);
|
| 578 | return EFI_SUCCESS;
|
| 579 | }
|
| 580 |
|
| 581 | if (EntryPointStructure->TableLength + InputStrLen - TargetStrLen > SMBIOS_TABLE_MAX_LENGTH) {
|
| 582 | //
|
| 583 | // The length of the entire structure table (including all strings) must be reported
|
| 584 | // in the Structure Table Length field of the SMBIOS Structure Table Entry Point,
|
| 585 | // which is a WORD field limited to 65,535 bytes.
|
| 586 | //
|
| 587 | return EFI_UNSUPPORTED;
|
| 588 | }
|
| 589 |
|
| 590 | //
|
| 591 | // Original string buffer size is not exactly match input string length.
|
| 592 | // Re-allocate buffer is needed.
|
| 593 | //
|
| 594 | NewEntrySize = SmbiosEntry->RecordSize + InputStrLen - TargetStrLen;
|
| 595 | ResizedSmbiosEntry = AllocateZeroPool (NewEntrySize);
|
| 596 |
|
| 597 | if (ResizedSmbiosEntry == NULL) {
|
| 598 | EfiReleaseLock (&Private->DataLock);
|
| 599 | return EFI_OUT_OF_RESOURCES;
|
| 600 | }
|
| 601 |
|
| 602 | InternalRecord = (EFI_SMBIOS_RECORD_HEADER *) (ResizedSmbiosEntry + 1);
|
| 603 | Raw = (VOID *) (InternalRecord + 1);
|
| 604 |
|
| 605 | //
|
| 606 | // Build internal record Header
|
| 607 | //
|
| 608 | InternalRecord->Version = EFI_SMBIOS_RECORD_HEADER_VERSION;
|
| 609 | InternalRecord->HeaderSize = (UINT16) sizeof (EFI_SMBIOS_RECORD_HEADER);
|
| 610 | InternalRecord->RecordSize = SmbiosEntry->RecordHeader->RecordSize + InputStrLen - TargetStrLen;
|
| 611 | InternalRecord->ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle;
|
| 612 | InternalRecord->NumberOfStrings = SmbiosEntry->RecordHeader->NumberOfStrings;
|
| 613 |
|
| 614 | //
|
| 615 | // Copy SMBIOS structure and optional strings.
|
| 616 | //
|
| 617 | CopyMem (Raw, SmbiosEntry->RecordHeader + 1, Record->Length + TargetStrOffset);
|
| 618 | CopyMem ((VOID*)((UINTN)Raw + Record->Length + TargetStrOffset), String, InputStrLen + 1);
|
| 619 | CopyMem ((CHAR8*)((UINTN)Raw + Record->Length + TargetStrOffset + InputStrLen + 1),
|
| 620 | (CHAR8*)Record + Record->Length + TargetStrOffset + TargetStrLen + 1,
|
| 621 | SmbiosEntry->RecordHeader->RecordSize - sizeof (EFI_SMBIOS_RECORD_HEADER) - Record->Length - TargetStrOffset - TargetStrLen - 1);
|
| 622 |
|
| 623 | //
|
| 624 | // Insert new record
|
| 625 | //
|
| 626 | ResizedSmbiosEntry->Signature = EFI_SMBIOS_ENTRY_SIGNATURE;
|
| 627 | ResizedSmbiosEntry->RecordHeader = InternalRecord;
|
| 628 | ResizedSmbiosEntry->RecordSize = NewEntrySize;
|
| 629 | InsertTailList (Link->ForwardLink, &ResizedSmbiosEntry->Link);
|
| 630 |
|
| 631 | //
|
| 632 | // Remove old record
|
| 633 | //
|
| 634 | RemoveEntryList(Link);
|
| 635 | FreePool(SmbiosEntry);
|
| 636 | //
|
| 637 | // Some UEFI drivers (such as network) need some information in SMBIOS table.
|
| 638 | // Here we create SMBIOS table and publish it in
|
| 639 | // configuration table, so other UEFI drivers can get SMBIOS table from
|
| 640 | // configuration table without depending on PI SMBIOS protocol.
|
| 641 | //
|
| 642 | SmbiosTableConstruction ();
|
| 643 | EfiReleaseLock (&Private->DataLock);
|
| 644 | return EFI_SUCCESS;
|
| 645 | }
|
| 646 | }
|
| 647 |
|
| 648 | EfiReleaseLock (&Private->DataLock);
|
| 649 | return EFI_INVALID_PARAMETER;
|
| 650 | }
|
| 651 |
|
| 652 | /**
|
| 653 | Remove an SMBIOS record.
|
| 654 |
|
| 655 | @param This The EFI_SMBIOS_PROTOCOL instance.
|
| 656 | @param SmbiosHandle The handle of the SMBIOS record to remove.
|
| 657 |
|
| 658 | @retval EFI_SUCCESS SMBIOS record was removed.
|
| 659 | @retval EFI_INVALID_PARAMETER SmbiosHandle does not specify a valid SMBIOS record.
|
| 660 |
|
| 661 | **/
|
| 662 | EFI_STATUS
|
| 663 | EFIAPI
|
| 664 | SmbiosRemove (
|
| 665 | IN CONST EFI_SMBIOS_PROTOCOL *This,
|
| 666 | IN EFI_SMBIOS_HANDLE SmbiosHandle
|
| 667 | )
|
| 668 | {
|
| 669 | LIST_ENTRY *Link;
|
| 670 | LIST_ENTRY *Head;
|
| 671 | EFI_STATUS Status;
|
| 672 | EFI_SMBIOS_HANDLE MaxSmbiosHandle;
|
| 673 | SMBIOS_INSTANCE *Private;
|
| 674 | EFI_SMBIOS_ENTRY *SmbiosEntry;
|
| 675 | SMBIOS_HANDLE_ENTRY *HandleEntry;
|
| 676 | EFI_SMBIOS_TABLE_HEADER *Record;
|
| 677 |
|
| 678 | //
|
| 679 | // Check args validity
|
| 680 | //
|
| 681 | GetMaxSmbiosHandle(This, &MaxSmbiosHandle);
|
| 682 |
|
| 683 | if (SmbiosHandle > MaxSmbiosHandle) {
|
| 684 | return EFI_INVALID_PARAMETER;
|
| 685 | }
|
| 686 |
|
| 687 | Private = SMBIOS_INSTANCE_FROM_THIS (This);
|
| 688 | //
|
| 689 | // Enter into critical section
|
| 690 | //
|
| 691 | Status = EfiAcquireLockOrFail (&Private->DataLock);
|
| 692 | if (EFI_ERROR (Status)) {
|
| 693 | return Status;
|
| 694 | }
|
| 695 |
|
| 696 | Head = &Private->DataListHead;
|
| 697 | for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
|
| 698 | SmbiosEntry = SMBIOS_ENTRY_FROM_LINK(Link);
|
| 699 | Record = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);
|
| 700 | if (Record->Handle == SmbiosHandle) {
|
| 701 | //
|
| 702 | // Remove specified smobios record from DataList
|
| 703 | //
|
| 704 | RemoveEntryList(Link);
|
| 705 | FreePool(SmbiosEntry);
|
| 706 | //
|
| 707 | // Remove this handle from AllocatedHandleList
|
| 708 | //
|
| 709 | Head = &Private->AllocatedHandleListHead;
|
| 710 | for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
|
| 711 | HandleEntry = SMBIOS_HANDLE_ENTRY_FROM_LINK(Link);
|
| 712 | if (HandleEntry->SmbiosHandle == SmbiosHandle) {
|
| 713 | RemoveEntryList(Link);
|
| 714 | FreePool(HandleEntry);
|
| 715 | break;
|
| 716 | }
|
| 717 | }
|
| 718 | //
|
| 719 | // Some UEFI drivers (such as network) need some information in SMBIOS table.
|
| 720 | // Here we create SMBIOS table and publish it in
|
| 721 | // configuration table, so other UEFI drivers can get SMBIOS table from
|
| 722 | // configuration table without depending on PI SMBIOS protocol.
|
| 723 | //
|
| 724 | SmbiosTableConstruction ();
|
| 725 | EfiReleaseLock (&Private->DataLock);
|
| 726 | return EFI_SUCCESS;
|
| 727 | }
|
| 728 | }
|
| 729 |
|
| 730 | //
|
| 731 | // Leave critical section
|
| 732 | //
|
| 733 | EfiReleaseLock (&Private->DataLock);
|
| 734 | return EFI_INVALID_PARAMETER;
|
| 735 |
|
| 736 | }
|
| 737 |
|
| 738 | /**
|
| 739 | Allow the caller to discover all or some of the SMBIOS records.
|
| 740 |
|
| 741 | @param This The EFI_SMBIOS_PROTOCOL instance.
|
| 742 | @param SmbiosHandle On entry, points to the previous handle of the SMBIOS record. On exit, points to the
|
| 743 | next SMBIOS record handle. If it is FFFEh on entry, then the first SMBIOS record
|
| 744 | handle will be returned. If it returns FFFEh on exit, then there are no more SMBIOS records.
|
| 745 | @param Type On entry it means return the next SMBIOS record of type Type. If a NULL is passed in
|
| 746 | this functionally it ignored. Type is not modified by the GetNext() function.
|
| 747 | @param Record On exit, points to the SMBIOS Record consisting of the formatted area followed by
|
| 748 | the unformatted area. The unformatted area optionally contains text strings.
|
| 749 | @param ProducerHandle On exit, points to the ProducerHandle registered by Add(). If no ProducerHandle was passed into Add() NULL is returned.
|
| 750 | If a NULL pointer is passed in no data will be returned
|
| 751 |
|
| 752 | @retval EFI_SUCCESS SMBIOS record information was successfully returned in Record.
|
| 753 | @retval EFI_NOT_FOUND The SMBIOS record with SmbiosHandle was the last available record.
|
| 754 |
|
| 755 | **/
|
| 756 | EFI_STATUS
|
| 757 | EFIAPI
|
| 758 | SmbiosGetNext (
|
| 759 | IN CONST EFI_SMBIOS_PROTOCOL *This,
|
| 760 | IN OUT EFI_SMBIOS_HANDLE *SmbiosHandle,
|
| 761 | IN EFI_SMBIOS_TYPE *Type, OPTIONAL
|
| 762 | OUT EFI_SMBIOS_TABLE_HEADER **Record,
|
| 763 | OUT EFI_HANDLE *ProducerHandle OPTIONAL
|
| 764 | )
|
| 765 | {
|
| 766 | BOOLEAN StartPointFound;
|
| 767 | LIST_ENTRY *Link;
|
| 768 | LIST_ENTRY *Head;
|
| 769 | SMBIOS_INSTANCE *Private;
|
| 770 | EFI_SMBIOS_ENTRY *SmbiosEntry;
|
| 771 | EFI_SMBIOS_TABLE_HEADER *SmbiosTableHeader;
|
| 772 |
|
| 773 | if (SmbiosHandle == NULL) {
|
| 774 | return EFI_INVALID_PARAMETER;
|
| 775 | }
|
| 776 |
|
| 777 | StartPointFound = FALSE;
|
| 778 | Private = SMBIOS_INSTANCE_FROM_THIS (This);
|
| 779 | Head = &Private->DataListHead;
|
| 780 | for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {
|
| 781 | SmbiosEntry = SMBIOS_ENTRY_FROM_LINK(Link);
|
| 782 | SmbiosTableHeader = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);
|
| 783 |
|
| 784 | //
|
| 785 | // If SmbiosHandle is 0xFFFE, the first matched SMBIOS record handle will be returned
|
| 786 | //
|
| 787 | if (*SmbiosHandle == SMBIOS_HANDLE_PI_RESERVED) {
|
| 788 | if ((Type != NULL) && (*Type != SmbiosTableHeader->Type)) {
|
| 789 | continue;
|
| 790 | }
|
| 791 |
|
| 792 | *SmbiosHandle = SmbiosTableHeader->Handle;
|
| 793 | *Record =SmbiosTableHeader;
|
| 794 | if (ProducerHandle != NULL) {
|
| 795 | *ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle;
|
| 796 | }
|
| 797 | return EFI_SUCCESS;
|
| 798 | }
|
| 799 |
|
| 800 | //
|
| 801 | // Start this round search from the next SMBIOS handle
|
| 802 | //
|
| 803 | if (!StartPointFound && (*SmbiosHandle == SmbiosTableHeader->Handle)) {
|
| 804 | StartPointFound = TRUE;
|
| 805 | continue;
|
| 806 | }
|
| 807 |
|
| 808 | if (StartPointFound) {
|
| 809 | if ((Type != NULL) && (*Type != SmbiosTableHeader->Type)) {
|
| 810 | continue;
|
| 811 | }
|
| 812 |
|
| 813 | *SmbiosHandle = SmbiosTableHeader->Handle;
|
| 814 | *Record = SmbiosTableHeader;
|
| 815 | if (ProducerHandle != NULL) {
|
| 816 | *ProducerHandle = SmbiosEntry->RecordHeader->ProducerHandle;
|
| 817 | }
|
| 818 |
|
| 819 | return EFI_SUCCESS;
|
| 820 | }
|
| 821 | }
|
| 822 |
|
| 823 | *SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
|
| 824 | return EFI_NOT_FOUND;
|
| 825 |
|
| 826 | }
|
| 827 |
|
| 828 | /**
|
| 829 | Allow the caller to discover all of the SMBIOS records.
|
| 830 |
|
| 831 | @param This The EFI_SMBIOS_PROTOCOL instance.
|
| 832 | @param CurrentSmbiosEntry On exit, points to the SMBIOS entry on the list which includes the returned SMBIOS record information.
|
| 833 | If *CurrentSmbiosEntry is NULL on entry, then the first SMBIOS entry on the list will be returned.
|
| 834 | @param Record On exit, points to the SMBIOS Record consisting of the formatted area followed by
|
| 835 | the unformatted area. The unformatted area optionally contains text strings.
|
| 836 |
|
| 837 | @retval EFI_SUCCESS SMBIOS record information was successfully returned in Record.
|
| 838 | *CurrentSmbiosEntry points to the SMBIOS entry which includes the returned SMBIOS record information.
|
| 839 | @retval EFI_NOT_FOUND There is no more SMBIOS entry.
|
| 840 |
|
| 841 | **/
|
| 842 | EFI_STATUS
|
| 843 | EFIAPI
|
| 844 | GetNextSmbiosRecord (
|
| 845 | IN CONST EFI_SMBIOS_PROTOCOL *This,
|
| 846 | IN OUT EFI_SMBIOS_ENTRY **CurrentSmbiosEntry,
|
| 847 | OUT EFI_SMBIOS_TABLE_HEADER **Record
|
| 848 | )
|
| 849 | {
|
| 850 | LIST_ENTRY *Link;
|
| 851 | LIST_ENTRY *Head;
|
| 852 | SMBIOS_INSTANCE *Private;
|
| 853 | EFI_SMBIOS_ENTRY *SmbiosEntry;
|
| 854 | EFI_SMBIOS_TABLE_HEADER *SmbiosTableHeader;
|
| 855 |
|
| 856 | Private = SMBIOS_INSTANCE_FROM_THIS (This);
|
| 857 | if (*CurrentSmbiosEntry == NULL) {
|
| 858 | //
|
| 859 | // Get the beginning of SMBIOS entry.
|
| 860 | //
|
| 861 | Head = &Private->DataListHead;
|
| 862 | } else {
|
| 863 | //
|
| 864 | // Get previous SMBIOS entry and make it as start point.
|
| 865 | //
|
| 866 | Head = &(*CurrentSmbiosEntry)->Link;
|
| 867 | }
|
| 868 |
|
| 869 | Link = Head->ForwardLink;
|
| 870 |
|
| 871 | if (Link == &Private->DataListHead) {
|
| 872 | //
|
| 873 | // If no more SMBIOS entry in the list, return not found.
|
| 874 | //
|
| 875 | return EFI_NOT_FOUND;
|
| 876 | }
|
| 877 |
|
| 878 | SmbiosEntry = SMBIOS_ENTRY_FROM_LINK(Link);
|
| 879 | SmbiosTableHeader = (EFI_SMBIOS_TABLE_HEADER*)(SmbiosEntry->RecordHeader + 1);
|
| 880 | *Record = SmbiosTableHeader;
|
| 881 | *CurrentSmbiosEntry = SmbiosEntry;
|
| 882 | return EFI_SUCCESS;
|
| 883 | }
|
| 884 |
|
| 885 | /**
|
| 886 | Assembles SMBIOS table from the SMBIOS protocol. Produce Table
|
| 887 | Entry Point and return the pointer to it.
|
| 888 |
|
| 889 | @param TableEntryPointStructure On exit, points to the SMBIOS entrypoint structure.
|
| 890 |
|
| 891 | @retval EFI_SUCCESS Structure created sucessfully.
|
| 892 | @retval EFI_NOT_READY Some of The SMBIOS records was not available yet.
|
| 893 | @retval EFI_OUT_OF_RESOURCES No enough memory.
|
| 894 |
|
| 895 | **/
|
| 896 | EFI_STATUS
|
| 897 | EFIAPI
|
| 898 | SmbiosCreateTable (
|
| 899 | OUT VOID **TableEntryPointStructure
|
| 900 | )
|
| 901 | {
|
| 902 | UINT8 *BufferPointer;
|
| 903 | UINTN RecordSize;
|
| 904 | UINTN NumOfStr;
|
| 905 | EFI_STATUS Status;
|
| 906 | EFI_SMBIOS_HANDLE SmbiosHandle;
|
| 907 | EFI_SMBIOS_PROTOCOL *SmbiosProtocol;
|
| 908 | EFI_PHYSICAL_ADDRESS PhysicalAddress;
|
| 909 | EFI_SMBIOS_TABLE_HEADER *SmbiosRecord;
|
| 910 | EFI_SMBIOS_TABLE_END_STRUCTURE EndStructure;
|
| 911 | EFI_SMBIOS_ENTRY *CurrentSmbiosEntry;
|
| 912 |
|
| 913 | Status = EFI_SUCCESS;
|
| 914 | BufferPointer = NULL;
|
| 915 |
|
| 916 | //
|
| 917 | // Get Smbios protocol to traverse SMBIOS records.
|
| 918 | //
|
| 919 | SmbiosProtocol = &mPrivateData.Smbios;
|
| 920 |
|
| 921 | //
|
| 922 | // Make some statistics about all the structures
|
| 923 | //
|
| 924 | EntryPointStructure->NumberOfSmbiosStructures = 0;
|
| 925 | EntryPointStructure->TableLength = 0;
|
| 926 | EntryPointStructure->MaxStructureSize = 0;
|
| 927 |
|
| 928 | //
|
| 929 | // Calculate EPS Table Length
|
| 930 | //
|
| 931 | CurrentSmbiosEntry = NULL;
|
| 932 | do {
|
| 933 | Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord);
|
| 934 |
|
| 935 | if (Status == EFI_SUCCESS) {
|
| 936 | GetSmbiosStructureSize(SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr);
|
| 937 | //
|
| 938 | // Record NumberOfSmbiosStructures, TableLength and MaxStructureSize
|
| 939 | //
|
| 940 | EntryPointStructure->NumberOfSmbiosStructures++;
|
| 941 | EntryPointStructure->TableLength = (UINT16) (EntryPointStructure->TableLength + RecordSize);
|
| 942 | if (RecordSize > EntryPointStructure->MaxStructureSize) {
|
| 943 | EntryPointStructure->MaxStructureSize = (UINT16) RecordSize;
|
| 944 | }
|
| 945 | }
|
| 946 | } while (!EFI_ERROR(Status));
|
| 947 |
|
| 948 | //
|
| 949 | // Create End-Of-Table structure
|
| 950 | //
|
| 951 | GetMaxSmbiosHandle(SmbiosProtocol, &SmbiosHandle);
|
| 952 | EndStructure.Header.Type = EFI_SMBIOS_TYPE_END_OF_TABLE;
|
| 953 | EndStructure.Header.Length = (UINT8) sizeof (EFI_SMBIOS_TABLE_HEADER);
|
| 954 | EndStructure.Header.Handle = SmbiosHandle;
|
| 955 | EndStructure.Tailing[0] = 0;
|
| 956 | EndStructure.Tailing[1] = 0;
|
| 957 | EntryPointStructure->NumberOfSmbiosStructures++;
|
| 958 | EntryPointStructure->TableLength = (UINT16) (EntryPointStructure->TableLength + sizeof (EndStructure));
|
| 959 | if (sizeof (EndStructure) > EntryPointStructure->MaxStructureSize) {
|
| 960 | EntryPointStructure->MaxStructureSize = (UINT16) sizeof (EndStructure);
|
| 961 | }
|
| 962 |
|
| 963 | if ((UINTN) EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength) > mPreAllocatedPages) {
|
| 964 | //
|
| 965 | // If new SMBIOS talbe size exceeds the original pre-allocated page,
|
| 966 | // it is time to re-allocate memory (below 4GB).
|
| 967 | //
|
| 968 | if (EntryPointStructure->TableAddress != 0) {
|
| 969 | //
|
| 970 | // Free the original pre-allocated page
|
| 971 | //
|
| 972 | FreePages (
|
| 973 | (VOID*)(UINTN)EntryPointStructure->TableAddress,
|
| 974 | mPreAllocatedPages
|
| 975 | );
|
| 976 | EntryPointStructure->TableAddress = 0;
|
| 977 | mPreAllocatedPages = 0;
|
| 978 | }
|
| 979 |
|
| 980 | PhysicalAddress = 0xffffffff;
|
| 981 | Status = gBS->AllocatePages (
|
| 982 | AllocateMaxAddress,
|
| 983 | EfiRuntimeServicesData,
|
| 984 | EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength),
|
| 985 | &PhysicalAddress
|
| 986 | );
|
| 987 | if (EFI_ERROR (Status)) {
|
| 988 | DEBUG ((EFI_D_ERROR, "SmbiosCreateTable() could not allocate SMBIOS table < 4GB\n"));
|
| 989 | EntryPointStructure->TableAddress = 0;
|
| 990 | return EFI_OUT_OF_RESOURCES;
|
| 991 | } else {
|
| 992 | EntryPointStructure->TableAddress = (UINT32) PhysicalAddress;
|
| 993 | mPreAllocatedPages = EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength);
|
| 994 | }
|
| 995 | }
|
| 996 |
|
| 997 | //
|
| 998 | // Assemble the tables
|
| 999 | //
|
| 1000 | ASSERT (EntryPointStructure->TableAddress != 0);
|
| 1001 | BufferPointer = (UINT8 *) (UINTN) EntryPointStructure->TableAddress;
|
| 1002 | CurrentSmbiosEntry = NULL;
|
| 1003 | do {
|
| 1004 | Status = GetNextSmbiosRecord (SmbiosProtocol, &CurrentSmbiosEntry, &SmbiosRecord);
|
| 1005 |
|
| 1006 | if (Status == EFI_SUCCESS) {
|
| 1007 | GetSmbiosStructureSize(SmbiosProtocol, SmbiosRecord, &RecordSize, &NumOfStr);
|
| 1008 | CopyMem (BufferPointer, SmbiosRecord, RecordSize);
|
| 1009 | BufferPointer = BufferPointer + RecordSize;
|
| 1010 | }
|
| 1011 | } while (!EFI_ERROR(Status));
|
| 1012 |
|
| 1013 | //
|
| 1014 | // Assemble End-Of-Table structure
|
| 1015 | //
|
| 1016 | CopyMem (BufferPointer, &EndStructure, sizeof (EndStructure));
|
| 1017 |
|
| 1018 | //
|
| 1019 | // Fixup checksums in the Entry Point Structure
|
| 1020 | //
|
| 1021 | EntryPointStructure->IntermediateChecksum = 0;
|
| 1022 | EntryPointStructure->EntryPointStructureChecksum = 0;
|
| 1023 |
|
| 1024 | EntryPointStructure->IntermediateChecksum =
|
| 1025 | CalculateCheckSum8 ((UINT8 *) EntryPointStructure + 0x10, EntryPointStructure->EntryPointLength - 0x10);
|
| 1026 | EntryPointStructure->EntryPointStructureChecksum =
|
| 1027 | CalculateCheckSum8 ((UINT8 *) EntryPointStructure, EntryPointStructure->EntryPointLength);
|
| 1028 |
|
| 1029 | //
|
| 1030 | // Returns the pointer
|
| 1031 | //
|
| 1032 | *TableEntryPointStructure = EntryPointStructure;
|
| 1033 |
|
| 1034 | return EFI_SUCCESS;
|
| 1035 | }
|
| 1036 |
|
| 1037 | /**
|
| 1038 | Create SMBIOS Table and install it to the System Table.
|
| 1039 | **/
|
| 1040 | VOID
|
| 1041 | EFIAPI
|
| 1042 | SmbiosTableConstruction (
|
| 1043 | VOID
|
| 1044 | )
|
| 1045 | {
|
| 1046 | UINT8 *Eps;
|
| 1047 | EFI_STATUS Status;
|
| 1048 |
|
| 1049 | Status = SmbiosCreateTable ((VOID **) &Eps);
|
| 1050 | if (!EFI_ERROR (Status)) {
|
| 1051 | gBS->InstallConfigurationTable (&gEfiSmbiosTableGuid, Eps);
|
| 1052 | }
|
| 1053 | }
|
| 1054 |
|
| 1055 | /**
|
| 1056 |
|
| 1057 | Driver to produce Smbios protocol and pre-allocate 1 page for the final SMBIOS table.
|
| 1058 |
|
| 1059 | @param ImageHandle Module's image handle
|
| 1060 | @param SystemTable Pointer of EFI_SYSTEM_TABLE
|
| 1061 |
|
| 1062 | @retval EFI_SUCCESS Smbios protocol installed
|
| 1063 | @retval Other No protocol installed, unload driver.
|
| 1064 |
|
| 1065 | **/
|
| 1066 | EFI_STATUS
|
| 1067 | EFIAPI
|
| 1068 | SmbiosDriverEntryPoint (
|
| 1069 | IN EFI_HANDLE ImageHandle,
|
| 1070 | IN EFI_SYSTEM_TABLE *SystemTable
|
| 1071 | )
|
| 1072 | {
|
| 1073 | EFI_STATUS Status;
|
| 1074 | EFI_PHYSICAL_ADDRESS PhysicalAddress;
|
| 1075 |
|
| 1076 | mPrivateData.Signature = SMBIOS_INSTANCE_SIGNATURE;
|
| 1077 | mPrivateData.Smbios.Add = SmbiosAdd;
|
| 1078 | mPrivateData.Smbios.UpdateString = SmbiosUpdateString;
|
| 1079 | mPrivateData.Smbios.Remove = SmbiosRemove;
|
| 1080 | mPrivateData.Smbios.GetNext = SmbiosGetNext;
|
| 1081 | mPrivateData.Smbios.MajorVersion = (UINT8) (PcdGet16 (PcdSmbiosVersion) >> 8);
|
| 1082 | mPrivateData.Smbios.MinorVersion = (UINT8) (PcdGet16 (PcdSmbiosVersion) & 0x00ff);
|
| 1083 | EntryPointStructureData.MajorVersion = mPrivateData.Smbios.MajorVersion;
|
| 1084 | EntryPointStructureData.MinorVersion = mPrivateData.Smbios.MinorVersion;
|
| 1085 | EntryPointStructureData.SmbiosBcdRevision = (UINT8) ((PcdGet16 (PcdSmbiosVersion) >> 4) & 0xf0) | (UINT8) (PcdGet16 (PcdSmbiosVersion) & 0x0f);
|
| 1086 |
|
| 1087 | InitializeListHead (&mPrivateData.DataListHead);
|
| 1088 | InitializeListHead (&mPrivateData.AllocatedHandleListHead);
|
| 1089 | EfiInitializeLock (&mPrivateData.DataLock, TPL_NOTIFY);
|
| 1090 |
|
| 1091 | //
|
| 1092 | // Initialize the EntryPointStructure with initial values.
|
| 1093 | // Allocate memory (below 4GB).
|
| 1094 | //
|
| 1095 | PhysicalAddress = 0xffffffff;
|
| 1096 | Status = gBS->AllocatePages (
|
| 1097 | AllocateMaxAddress,
|
| 1098 | EfiRuntimeServicesData,
|
| 1099 | EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT)),
|
| 1100 | &PhysicalAddress
|
| 1101 | );
|
| 1102 | if (EFI_ERROR (Status)) {
|
| 1103 | DEBUG ((EFI_D_ERROR, "SmbiosDriverEntryPoint() could not allocate EntryPointStructure < 4GB\n"));
|
| 1104 | Status = gBS->AllocatePages (
|
| 1105 | AllocateAnyPages,
|
| 1106 | EfiRuntimeServicesData,
|
| 1107 | EFI_SIZE_TO_PAGES (sizeof (SMBIOS_TABLE_ENTRY_POINT)),
|
| 1108 | &PhysicalAddress
|
| 1109 | );
|
| 1110 | if (EFI_ERROR (Status)) {
|
| 1111 | return EFI_OUT_OF_RESOURCES;
|
| 1112 | }
|
| 1113 | }
|
| 1114 |
|
| 1115 | EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *) (UINTN) PhysicalAddress;
|
| 1116 |
|
| 1117 | CopyMem (
|
| 1118 | EntryPointStructure,
|
| 1119 | &EntryPointStructureData,
|
| 1120 | sizeof (SMBIOS_TABLE_ENTRY_POINT)
|
| 1121 | );
|
| 1122 |
|
| 1123 | //
|
| 1124 | // Pre-allocate 1 page for SMBIOS table below 4GB.
|
| 1125 | // SMBIOS table will be updated when new SMBIOS type is added or
|
| 1126 | // existing SMBIOS type is updated. If the total size of SMBIOS table exceeds 1 page,
|
| 1127 | // we will re-allocate new memory when creating whole SMBIOS table.
|
| 1128 | //
|
| 1129 | PhysicalAddress = 0xffffffff;
|
| 1130 | Status = gBS->AllocatePages (
|
| 1131 | AllocateMaxAddress,
|
| 1132 | EfiRuntimeServicesData,
|
| 1133 | 1,
|
| 1134 | &PhysicalAddress
|
| 1135 | );
|
| 1136 | if (EFI_ERROR (Status)) {
|
| 1137 | DEBUG ((EFI_D_ERROR, "SmbiosDriverEntryPoint() could not allocate SMBIOS table < 4GB\n"));
|
| 1138 | EntryPointStructure->TableAddress = 0;
|
| 1139 | } else {
|
| 1140 | EntryPointStructure->TableAddress = (UINT32) PhysicalAddress;
|
| 1141 | mPreAllocatedPages = 1;
|
| 1142 | }
|
| 1143 |
|
| 1144 | //
|
| 1145 | // Init TableLength to the length of End-Of-Table structure for SmbiosAdd() called at the first time
|
| 1146 | // to check the TableLength limitation.
|
| 1147 | //
|
| 1148 | EntryPointStructure->TableLength = sizeof (EFI_SMBIOS_TABLE_END_STRUCTURE);
|
| 1149 |
|
| 1150 | //
|
| 1151 | // Make a new handle and install the protocol
|
| 1152 | //
|
| 1153 | mPrivateData.Handle = NULL;
|
| 1154 | Status = gBS->InstallProtocolInterface (
|
| 1155 | &mPrivateData.Handle,
|
| 1156 | &gEfiSmbiosProtocolGuid,
|
| 1157 | EFI_NATIVE_INTERFACE,
|
| 1158 | &mPrivateData.Smbios
|
| 1159 | );
|
| 1160 |
|
| 1161 | return Status;
|
| 1162 | }
|