/** @file
  Static SMBIOS Table for platform


  Copyright (c) 2012, Apple Inc. All rights reserved.<BR>
  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include <PiDxe.h>
#include <IndustryStandard/SmBios.h>
#include <Protocol/Smbios.h>

#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/SmbiosLib.h>
#include <Library/HobLib.h>

extern SMBIOS_TEMPLATE_ENTRY  gSmbiosTemplate[];

SMBIOS_TABLE_TYPE19  gSmbiosType19Template = {
  { EFI_SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS, sizeof (SMBIOS_TABLE_TYPE19), 0 },
  0xffffffff, // StartingAddress;
  0xffffffff, // EndingAddress;
  0,          // MemoryArrayHandle;
  1,          // PartitionWidth;
  0,          // ExtendedStartingAddress;
  0,          // ExtendedEndingAddress;
};

VOID
CreatePlatformSmbiosMemoryRecords (
  VOID
  )
{
  EFI_PEI_HOB_POINTERS      HobPtr;
  SMBIOS_STRUCTURE_POINTER  Smbios16;
  SMBIOS_STRUCTURE_POINTER  Smbios17;
  EFI_SMBIOS_HANDLE         PhyscialMemoryArrayHandle;
  EFI_SMBIOS_HANDLE         SmbiosHandle;

  Smbios16.Hdr = SmbiosLibGetRecord (EFI_SMBIOS_TYPE_PHYSICAL_MEMORY_ARRAY, 0, &PhyscialMemoryArrayHandle);
  if (Smbios16.Hdr == NULL) {
    // Only make a Type19 entry if a Type16 entry exists.
    return;
  }

  Smbios17.Hdr = SmbiosLibGetRecord (EFI_SMBIOS_TYPE_MEMORY_DEVICE, 0, &SmbiosHandle);
  if (Smbios17.Hdr == NULL) {
    // if type17 exits update with type16 Smbios handle
    Smbios17.Type17->MemoryArrayHandle = PhyscialMemoryArrayHandle;
  }

  // Generate Type16 records
  gSmbiosType19Template.MemoryArrayHandle = PhyscialMemoryArrayHandle;
  HobPtr.Raw                              = GetHobList ();
  while ((HobPtr.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, HobPtr.Raw)) != NULL) {
    if (HobPtr.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {
      gSmbiosType19Template.ExtendedStartingAddress = HobPtr.ResourceDescriptor->PhysicalStart;
      gSmbiosType19Template.ExtendedEndingAddress   =
        HobPtr.ResourceDescriptor->PhysicalStart +
        HobPtr.ResourceDescriptor->ResourceLength - 1;

      SmbiosLibCreateEntry ((SMBIOS_STRUCTURE *)&gSmbiosType19Template, NULL);
    }

    HobPtr.Raw = GET_NEXT_HOB (HobPtr);
  }
}

/**
  Main entry for this driver.

  @param ImageHandle     Image handle this driver.
  @param SystemTable     Pointer to SystemTable.

  @retval EFI_SUCESS     This function always complete successfully.

**/
EFI_STATUS
EFIAPI
PlatformSmbiosDriverEntryPoint (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS                Status;
  EFI_SMBIOS_HANDLE         SmbiosHandle;
  SMBIOS_STRUCTURE_POINTER  Smbios;

  // Phase 0 - Patch table to make SMBIOS 2.7 structures smaller to conform
  //           to an early version of the specification.

  // Phase 1 - Initialize SMBIOS tables from template
  Status = SmbiosLibInitializeFromTemplate (gSmbiosTemplate);
  ASSERT_EFI_ERROR (Status);

  // Phase 2 - Patch SMBIOS table entries

  Smbios.Hdr = SmbiosLibGetRecord (EFI_SMBIOS_TYPE_BIOS_INFORMATION, 0, &SmbiosHandle);
  if (Smbios.Type0 != NULL) {
    // 64K * (n+1) bytes
    Smbios.Type0->BiosSize = (UINT8)DivU64x32 (FixedPcdGet64 (PcdEmuFirmwareFdSize), 64*1024) - 1;

    SmbiosLibUpdateUnicodeString (
      SmbiosHandle,
      Smbios.Type0->BiosVersion,
      (CHAR16 *)PcdGetPtr (PcdFirmwareVersionString)
      );
    SmbiosLibUpdateUnicodeString (
      SmbiosHandle,
      Smbios.Type0->BiosReleaseDate,
      (CHAR16 *)PcdGetPtr (PcdFirmwareReleaseDateString)
      );
  }

  // Phase 3 - Create tables from scratch

  // Create Type 13 record from EFI Variables
  // Do we need this record for EFI as the info is available from EFI varaibles
  // Also language types don't always match between EFI and SMBIOS
  // CreateSmbiosLanguageInformation (1, gSmbiosLangToEfiLang);

  CreatePlatformSmbiosMemoryRecords ();

  return EFI_SUCCESS;
}
