/** @file
  Copyright (c) 2021, Intel Corporation. All rights reserved.
  SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "PeilessStartupInternal.h"
#define GET_GPAW_INIT_STATE(INFO)  ((UINT8) ((INFO) & 0x3f))
EFI_MEMORY_TYPE_INFORMATION  mDefaultMemoryTypeInformation[] = {
  { EfiACPIMemoryNVS,       0x004 },
  { EfiACPIReclaimMemory,   0x008 },
  { EfiReservedMemoryType,  0x004 },
  { EfiRuntimeServicesData, 0x024 },
  { EfiRuntimeServicesCode, 0x030 },
  { EfiBootServicesCode,    0x180 },
  { EfiBootServicesData,    0xF00 },
  { EfiMaxMemoryType,       0x000 }
};
EFI_STATUS
EFIAPI
InitializePlatform (
  EFI_HOB_PLATFORM_INFO  *PlatformInfoHob
  )
{
  VOID  *VariableStore;
  DEBUG ((DEBUG_INFO, "InitializePlatform in Pei-less boot\n"));
  PlatformDebugDumpCmos ();
  PlatformInfoHob->DefaultMaxCpuNumber = 64;
  PlatformInfoHob->PcdPciMmio64Size    = 0x800000000;
  PlatformInfoHob->HostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);
  DEBUG ((DEBUG_INFO, "HostBridgeDeviceId = 0x%x\n", PlatformInfoHob->HostBridgeDevId));
  PlatformAddressWidthInitialization (PlatformInfoHob);
  DEBUG ((
    DEBUG_INFO,
    "PhysMemAddressWidth=0x%x, Pci64Base=0x%llx, Pci64Size=0x%llx\n",
    PlatformInfoHob->PhysMemAddressWidth,
    PlatformInfoHob->PcdPciMmio64Base,
    PlatformInfoHob->PcdPciMmio64Size
    ));
  PlatformMaxCpuCountInitialization (PlatformInfoHob);
  DEBUG ((
    DEBUG_INFO,
    "MaxCpuCount=%d, BootCpuCount=%d\n",
    PlatformInfoHob->PcdCpuMaxLogicalProcessorNumber,
    PlatformInfoHob->PcdCpuBootLogicalProcessorNumber
    ));
  PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob);
  PlatformQemuUc32BaseInitialization (PlatformInfoHob);
  DEBUG ((
    DEBUG_INFO,
    "Uc32Base = 0x%x, Uc32Size = 0x%x, LowerMemorySize = 0x%x\n",
    PlatformInfoHob->Uc32Base,
    PlatformInfoHob->Uc32Size,
    PlatformInfoHob->LowMemory
    ));
  VariableStore                                  = PlatformReserveEmuVariableNvStore ();
  PlatformInfoHob->PcdEmuVariableNvStoreReserved = (UINT64)(UINTN)VariableStore;
  if (FeaturePcdGet (PcdSecureBootSupported)) {
    PlatformInitEmuVariableNvStore (VariableStore);
  }
  if (TdIsEnabled ()) {
    PlatformTdxPublishRamRegions ();
  } else {
    PlatformQemuInitializeRam (PlatformInfoHob);
    PlatformQemuInitializeRamForS3 (PlatformInfoHob);
  }
  //
  // Create Memory Type Information HOB
  //
  BuildGuidDataHob (
    &gEfiMemoryTypeInformationGuid,
    mDefaultMemoryTypeInformation,
    sizeof (mDefaultMemoryTypeInformation)
    );
  PlatformMemMapInitialization (PlatformInfoHob);
  PlatformNoexecDxeInitialization (PlatformInfoHob);
  if (TdIsEnabled ()) {
    PlatformInfoHob->PcdConfidentialComputingGuestAttr = CCAttrIntelTdx;
    PlatformInfoHob->PcdTdxSharedBitMask               = TdSharedPageMask ();
    PlatformInfoHob->PcdSetNxForStack                  = TRUE;
  }
  PlatformMiscInitialization (PlatformInfoHob);
  return EFI_SUCCESS;
}
/**
 * This function brings up the Tdx guest from SEC phase to DXE phase.
 * PEI phase is skipped because most of the components in PEI phase
 * is not needed for Tdx guest, for example, MP Services, TPM etc.
 * In this way, the attack surfaces are reduced as much as possible.
 *
 * @param Context   The pointer to the SecCoreData
 * @return VOID     This function never returns
 */
VOID
EFIAPI
PeilessStartup (
  IN VOID  *Context
  )
{
  EFI_SEC_PEI_HAND_OFF        *SecCoreData;
  EFI_FIRMWARE_VOLUME_HEADER  *BootFv;
  EFI_STATUS                  Status;
  EFI_HOB_PLATFORM_INFO       PlatformInfoHob;
  UINT32                      DxeCodeBase;
  UINT32                      DxeCodeSize;
  TD_RETURN_DATA              TdReturnData;
  VOID                        *VmmHobList;
  Status      = EFI_SUCCESS;
  BootFv      = NULL;
  VmmHobList  = NULL;
  SecCoreData = (EFI_SEC_PEI_HAND_OFF *)Context;
  ZeroMem (&PlatformInfoHob, sizeof (PlatformInfoHob));
  if (TdIsEnabled ()) {
    VmmHobList = (VOID *)(UINTN)FixedPcdGet32 (PcdOvmfSecGhcbBase);
    Status     = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
    ASSERT (Status == EFI_SUCCESS);
    DEBUG ((
      DEBUG_INFO,
      "Tdx started with(Hob: 0x%x, Gpaw: 0x%x, Cpus: %d)\n",
      (UINT32)(UINTN)VmmHobList,
      GET_GPAW_INIT_STATE (TdReturnData.TdInfo.Gpaw),
      TdReturnData.TdInfo.NumVcpus
      ));
    Status = ConstructFwHobList (VmmHobList);
  } else {
    DEBUG ((DEBUG_INFO, "Ovmf started\n"));
    Status = ConstructSecHobList ();
  }
  if (EFI_ERROR (Status)) {
    ASSERT (FALSE);
    CpuDeadLoop ();
  }
  DEBUG ((DEBUG_INFO, "HobList: %p\n", GetHobList ()));
  if (TdIsEnabled ()) {
    //
    // Build GuidHob for the tdx measurements which were done in SEC phase.
    //
    Status = TdxHelperBuildGuidHobForTdxMeasurement ();
    if (EFI_ERROR (Status)) {
      ASSERT (FALSE);
      CpuDeadLoop ();
    }
  }
  //
  // Initialize the Platform
  //
  Status = InitializePlatform (&PlatformInfoHob);
  if (EFI_ERROR (Status)) {
    ASSERT (FALSE);
    CpuDeadLoop ();
  }
  BuildGuidDataHob (&gUefiOvmfPkgPlatformInfoGuid, &PlatformInfoHob, sizeof (EFI_HOB_PLATFORM_INFO));
  //
  // SecFV
  //
  BootFv = (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase;
  BuildFvHob ((UINTN)BootFv, BootFv->FvLength);
  //
  // DxeFV
  //
  DxeCodeBase = PcdGet32 (PcdBfvBase);
  DxeCodeSize = PcdGet32 (PcdBfvRawDataSize) - (UINT32)BootFv->FvLength;
  BuildFvHob (DxeCodeBase, DxeCodeSize);
  DEBUG ((DEBUG_INFO, "SecFv : %p, 0x%x\n", BootFv, BootFv->FvLength));
  DEBUG ((DEBUG_INFO, "DxeFv : %x, 0x%x\n", DxeCodeBase, DxeCodeSize));
  BuildStackHob ((UINTN)SecCoreData->StackBase, SecCoreData->StackSize <<= 1);
  BuildResourceDescriptorHob (
    EFI_RESOURCE_SYSTEM_MEMORY,
    EFI_RESOURCE_ATTRIBUTE_PRESENT |
    EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
    EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
    EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
    EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
    EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
    EFI_RESOURCE_ATTRIBUTE_TESTED,
    (UINT64)SecCoreData->TemporaryRamBase,
    (UINT64)SecCoreData->TemporaryRamSize
    );
  //
  // Load the DXE Core and transfer control to it.
  // Only DxeFV is in the compressed section.
  //
  Status = DxeLoadCore (1);
  //
  // Never arrive here.
  //
  ASSERT (FALSE);
  CpuDeadLoop ();
}