/** Add an SMBIOS record. @param This The EFI_SMBIOS_PROTOCOL instance. @param ProducerHandle The handle of the controller or driver associated with the SMBIOS information. NULL means no handle. @param SmbiosHandle On entry, if non-zero, the handle of the SMBIOS record. If zero, then a unique handle will be assigned to the SMBIOS record. If the SMBIOS handle is already in use EFI_ALREADY_STARTED is returned and the SMBIOS record is not updated. @param Record The data for the fixed portion of the SMBIOS record. The format of the record is determined by EFI_SMBIOS_TABLE_HEADER.Type. The size of the formatted area is defined by EFI_SMBIOS_TABLE_HEADER.Length and either followed by a double-null (0x0000) or a set of null terminated strings and a null. @retval EFI_SUCCESS Record was added. @retval EFI_OUT_OF_RESOURCES Record was not added due to lack of system resources. @retval EFI_ALREADY_STARTED The SmbiosHandle passed in was already in use. **/ EFI_STATUS EFIAPI SmbiosAdd ( IN CONST EFI_SMBIOS_PROTOCOL *This, IN EFI_HANDLE ProducerHandle, OPTIONAL IN OUT EFI_SMBIOS_HANDLE *SmbiosHandle, IN EFI_SMBIOS_TABLE_HEADER *Record ) { VOID *Raw; UINTN TotalSize; UINTN RecordSize; UINTN StructureSize; UINTN NumberOfStrings; EFI_STATUS Status; LIST_ENTRY *Head; SMBIOS_INSTANCE *Private; EFI_SMBIOS_ENTRY *SmbiosEntry; EFI_SMBIOS_HANDLE MaxSmbiosHandle; SMBIOS_HANDLE_ENTRY *HandleEntry; EFI_SMBIOS_RECORD_HEADER *InternalRecord; if (SmbiosHandle == NULL) { return EFI_INVALID_PARAMETER; } Private = SMBIOS_INSTANCE_FROM_THIS (This); // // Check whether SmbiosHandle is already in use // Head = &Private->AllocatedHandleListHead; if (*SmbiosHandle != 0 && CheckSmbiosHandleExistance(Head, *SmbiosHandle)) { return EFI_ALREADY_STARTED; } // // when SmbiosHandle is zero, an available handle will be assigned // if (*SmbiosHandle == 0) { Status = GetAvailableSmbiosHandle(This, SmbiosHandle); if (EFI_ERROR(Status)) { return Status; } } else { // // Check this handle validity // GetMaxSmbiosHandle(This, &MaxSmbiosHandle); if (*SmbiosHandle > MaxSmbiosHandle) { return EFI_INVALID_PARAMETER; } } // // Calculate record size and string number // Status = GetSmbiosStructureSize(This, Record, &StructureSize, &NumberOfStrings); if (EFI_ERROR(Status)) { return Status; } // // Enter into critical section // Status = EfiAcquireLockOrFail (&Private->DataLock); if (EFI_ERROR (Status)) { return Status; } RecordSize = sizeof (EFI_SMBIOS_RECORD_HEADER) + StructureSize; TotalSize = sizeof (EFI_SMBIOS_ENTRY) + RecordSize; // // Allocate internal buffer // SmbiosEntry = AllocateZeroPool (TotalSize); if (SmbiosEntry == NULL) { EfiReleaseLock (&Private->DataLock); return EFI_OUT_OF_RESOURCES; } HandleEntry = AllocateZeroPool (sizeof(SMBIOS_HANDLE_ENTRY)); if (HandleEntry == NULL) { EfiReleaseLock (&Private->DataLock); return EFI_OUT_OF_RESOURCES; } // // Build Handle Entry and insert into linked list // HandleEntry->Signature = SMBIOS_HANDLE_ENTRY_SIGNATURE; HandleEntry->SmbiosHandle = *SmbiosHandle; InsertTailList(&Private->AllocatedHandleListHead, &HandleEntry->Link); InternalRecord = (EFI_SMBIOS_RECORD_HEADER *) (SmbiosEntry + 1); Raw = (VOID *) (InternalRecord + 1); // // Build internal record Header // InternalRecord->Version = EFI_SMBIOS_RECORD_HEADER_VERSION; InternalRecord->HeaderSize = (UINT16) sizeof (EFI_SMBIOS_RECORD_HEADER); InternalRecord->RecordSize = RecordSize; InternalRecord->ProducerHandle = ProducerHandle; InternalRecord->NumberOfStrings = NumberOfStrings; // // Insert record into the internal linked list // SmbiosEntry->Signature = EFI_SMBIOS_ENTRY_SIGNATURE; SmbiosEntry->RecordHeader = InternalRecord; SmbiosEntry->RecordSize = TotalSize; InsertTailList (&Private->DataListHead, &SmbiosEntry->Link); CopyMem (Raw, Record, StructureSize); ((EFI_SMBIOS_TABLE_HEADER*)Raw)->Handle = *SmbiosHandle; // // Leave critical section // EfiReleaseLock (&Private->DataLock); return EFI_SUCCESS; }
/** Add an SMBIOS record. @param This The EFI_SMBIOS_PROTOCOL instance. @param ProducerHandle The handle of the controller or driver associated with the SMBIOS information. NULL means no handle. @param SmbiosHandle On entry, the handle of the SMBIOS record to add. If FFFEh, then a unique handle will be assigned to the SMBIOS record. If the SMBIOS handle is already in use, EFI_ALREADY_STARTED is returned and the SMBIOS record is not updated. @param Record The data for the fixed portion of the SMBIOS record. The format of the record is determined by EFI_SMBIOS_TABLE_HEADER.Type. The size of the formatted area is defined by EFI_SMBIOS_TABLE_HEADER.Length and either followed by a double-null (0x0000) or a set of null terminated strings and a null. @retval EFI_SUCCESS Record was added. @retval EFI_OUT_OF_RESOURCES Record was not added due to lack of system resources. @retval EFI_ALREADY_STARTED The SmbiosHandle passed in was already in use. **/ EFI_STATUS EFIAPI SmbiosAdd ( IN CONST EFI_SMBIOS_PROTOCOL *This, IN EFI_HANDLE ProducerHandle, OPTIONAL IN OUT EFI_SMBIOS_HANDLE *SmbiosHandle, IN EFI_SMBIOS_TABLE_HEADER *Record ) { VOID *Raw; UINTN TotalSize; UINTN RecordSize; UINTN StructureSize; UINTN NumberOfStrings; EFI_STATUS Status; LIST_ENTRY *Head; SMBIOS_INSTANCE *Private; EFI_SMBIOS_ENTRY *SmbiosEntry; EFI_SMBIOS_HANDLE MaxSmbiosHandle; SMBIOS_HANDLE_ENTRY *HandleEntry; EFI_SMBIOS_RECORD_HEADER *InternalRecord; BOOLEAN Smbios32BitTable; BOOLEAN Smbios64BitTable; if (SmbiosHandle == NULL) { return EFI_INVALID_PARAMETER; } Private = SMBIOS_INSTANCE_FROM_THIS (This); // // Check whether SmbiosHandle is already in use // Head = &Private->AllocatedHandleListHead; if (*SmbiosHandle != SMBIOS_HANDLE_PI_RESERVED && CheckSmbiosHandleExistance(Head, *SmbiosHandle)) { return EFI_ALREADY_STARTED; } // // when SmbiosHandle is 0xFFFE, an available handle will be assigned // if (*SmbiosHandle == SMBIOS_HANDLE_PI_RESERVED) { Status = GetAvailableSmbiosHandle(This, SmbiosHandle); if (EFI_ERROR(Status)) { return Status; } } else { // // Check this handle validity // GetMaxSmbiosHandle(This, &MaxSmbiosHandle); if (*SmbiosHandle > MaxSmbiosHandle) { return EFI_INVALID_PARAMETER; } } // // Calculate record size and string number // Status = GetSmbiosStructureSize(This, Record, &StructureSize, &NumberOfStrings); if (EFI_ERROR(Status)) { return Status; } Smbios32BitTable = FALSE; Smbios64BitTable = FALSE; if ((This->MajorVersion < 0x3) || ((This->MajorVersion >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT0) == BIT0))) { // // For SMBIOS 32-bit table, the length of the entire structure table (including all strings) must be reported // in the Structure Table Length field of the SMBIOS Structure Table Entry Point, // which is a WORD field limited to 65,535 bytes. So the max size of 32-bit table should not exceed 65,535 bytes. // if ((EntryPointStructure != NULL) && (EntryPointStructure->TableLength + StructureSize > SMBIOS_TABLE_MAX_LENGTH)) { DEBUG ((EFI_D_INFO, "SmbiosAdd: Total length exceeds max 32-bit table length with type = %d size = 0x%x\n", Record->Type, StructureSize)); } else { Smbios32BitTable = TRUE; DEBUG ((EFI_D_INFO, "SmbiosAdd: Smbios type %d with size 0x%x is added to 32-bit table\n", Record->Type, StructureSize)); } } // // For SMBIOS 3.0, Structure table maximum size in Entry Point structure is DWORD field limited to 0xFFFFFFFF bytes. // if ((This->MajorVersion >= 0x3) && ((PcdGet32 (PcdSmbiosEntryPointProvideMethod) & BIT1) == BIT1)) { // // For SMBIOS 64-bit table, Structure table maximum size in SMBIOS 3.0 (64-bit) Entry Point // is a DWORD field limited to 0xFFFFFFFF bytes. So the max size of 64-bit table should not exceed 0xFFFFFFFF bytes. // if ((Smbios30EntryPointStructure != NULL) && (Smbios30EntryPointStructure->TableMaximumSize + StructureSize > SMBIOS_3_0_TABLE_MAX_LENGTH)) { DEBUG ((EFI_D_INFO, "SmbiosAdd: Total length exceeds max 64-bit table length with type = %d size = 0x%x\n", Record->Type, StructureSize)); } else { DEBUG ((EFI_D_INFO, "SmbiosAdd: Smbios type %d with size 0x%x is added to 64-bit table\n", Record->Type, StructureSize)); Smbios64BitTable = TRUE; } } if ((!Smbios32BitTable) && (!Smbios64BitTable)) { // // If both 32-bit and 64-bit table are not updated, quit // return EFI_OUT_OF_RESOURCES; } // // Enter into critical section // Status = EfiAcquireLockOrFail (&Private->DataLock); if (EFI_ERROR (Status)) { return Status; } RecordSize = sizeof (EFI_SMBIOS_RECORD_HEADER) + StructureSize; TotalSize = sizeof (EFI_SMBIOS_ENTRY) + RecordSize; // // Allocate internal buffer // SmbiosEntry = AllocateZeroPool (TotalSize); if (SmbiosEntry == NULL) { EfiReleaseLock (&Private->DataLock); return EFI_OUT_OF_RESOURCES; } HandleEntry = AllocateZeroPool (sizeof(SMBIOS_HANDLE_ENTRY)); if (HandleEntry == NULL) { EfiReleaseLock (&Private->DataLock); return EFI_OUT_OF_RESOURCES; } // // Build Handle Entry and insert into linked list // HandleEntry->Signature = SMBIOS_HANDLE_ENTRY_SIGNATURE; HandleEntry->SmbiosHandle = *SmbiosHandle; InsertTailList(&Private->AllocatedHandleListHead, &HandleEntry->Link); InternalRecord = (EFI_SMBIOS_RECORD_HEADER *) (SmbiosEntry + 1); Raw = (VOID *) (InternalRecord + 1); // // Build internal record Header // InternalRecord->Version = EFI_SMBIOS_RECORD_HEADER_VERSION; InternalRecord->HeaderSize = (UINT16) sizeof (EFI_SMBIOS_RECORD_HEADER); InternalRecord->RecordSize = RecordSize; InternalRecord->ProducerHandle = ProducerHandle; InternalRecord->NumberOfStrings = NumberOfStrings; // // Insert record into the internal linked list // SmbiosEntry->Signature = EFI_SMBIOS_ENTRY_SIGNATURE; SmbiosEntry->RecordHeader = InternalRecord; SmbiosEntry->RecordSize = TotalSize; SmbiosEntry->Smbios32BitTable = Smbios32BitTable; SmbiosEntry->Smbios64BitTable = Smbios64BitTable; InsertTailList (&Private->DataListHead, &SmbiosEntry->Link); CopyMem (Raw, Record, StructureSize); ((EFI_SMBIOS_TABLE_HEADER*)Raw)->Handle = *SmbiosHandle; // // Some UEFI drivers (such as network) need some information in SMBIOS table. // Here we create SMBIOS table and publish it in // configuration table, so other UEFI drivers can get SMBIOS table from // configuration table without depending on PI SMBIOS protocol. // SmbiosTableConstruction (Smbios32BitTable, Smbios64BitTable); // // Leave critical section // EfiReleaseLock (&Private->DataLock); return EFI_SUCCESS; }