Example #1
0
/**

  Configure ECC scrub

  @param MrcData - MRC configuration

**/
VOID
EccScrubSetup(
  const MRC_PARAMS *MrcData
  )
{
  UINT32 BgnAdr = 0;
  UINT32 EndAdr = MrcData->mem_size;
  UINT32 BlkSize = GetEccScrubBlkSize() & SCRUB_CFG_BLOCKSIZE_MASK;
  UINT32 Interval = GetEccScrubInterval() & SCRUB_CFG_INTERVAL_MASK;

  if( MrcData->ecc_enables == 0 || MrcData->boot_mode == bmS3 || Interval == 0) {
    // No scrub configuration needed if ECC not enabled
    // On S3 resume reconfiguration is done as part of resume
    // script, see SNCS3Save.c ==> SaveRuntimeScriptTable()
    // Also if PCD disables scrub, then we do nothing.
    return;
  }

  QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_END_MEM_REG, EndAdr);
  QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_START_MEM_REG, BgnAdr);
  QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_NEXT_READ_REG, BgnAdr);
  QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_CONFIG_REG,
    Interval << SCRUB_CFG_INTERVAL_SHIFT |
    BlkSize << SCRUB_CFG_BLOCKSIZE_SHIFT);

  McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = SCRUB_RESUME_MSG();
}
Example #2
0
/**
  Platform specific mechanism to transfer control to 16bit OS waking vector

  @param[in] AcpiWakingVector    The 16bit OS waking vector
  @param[in] AcpiLowMemoryBase   A buffer under 1M which could be used during the transfer

**/
VOID
PlatformTransferControl16 (
    IN UINT32       AcpiWakingVector,
    IN UINT32       AcpiLowMemoryBase
)
{
    UINT32      NewValue;
    UINT64      BaseAddress;
    UINT64      SmramLength;
    UINTN       Index;

    DEBUG (( EFI_D_INFO, "PlatformTransferControl - Entry\r\n"));

    //
    // Need to make sure the GDT is loaded with values that support long mode and real mode.
    //
    AsmWriteGdtr (&mGdt);

    //
    // Disable eSram block (this will also clear/zero eSRAM)
    // We only use eSRAM in the PEI phase. Disable now that we are resuming the OS
    //
    NewValue = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_ESRAMPGCTRL_BLOCK);
    NewValue |= BLOCK_DISABLE_PG;
    QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_ESRAMPGCTRL_BLOCK, NewValue);

    //
    // Update HMBOUND to top of DDR3 memory and LOCK
    // We disabled eSRAM so now we move HMBOUND down to top of DDR3
    //
    QNCGetTSEGMemoryRange (&BaseAddress, &SmramLength);
    NewValue = (UINT32)(BaseAddress + SmramLength);
    DEBUG ((EFI_D_INFO,"Locking HMBOUND at: = 0x%8x\n",NewValue));
    QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HMBOUND_REG, (NewValue | HMBOUND_LOCK));

    //
    // Lock all IMR regions now that HMBOUND is locked
    //
    for (Index = (QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXL); Index <= (QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXL); Index += 4) {
        NewValue = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, Index);
        NewValue |= IMR_LOCK;
        QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, Index, NewValue);
    }

    //
    // Call ASM routine to switch to real mode and jump to 16bit OS waking vector
    //
    AsmTransferControl(AcpiWakingVector, 0);

    //
    // Never run to here
    //
    CpuDeadLoop();
}
Example #3
0
/**
  Triggers a run time or boot time SMI.

  This function triggers a software SMM interrupt and set the APMC status with an 8-bit Data.

  @param  Data                 The value to set the APMC status.

**/
VOID
InternalTriggerSmi (
  IN UINT8                     Data
  )
{
  UINT16        PM1BLK_Base;
  UINT16        GPE0BLK_Base;
  UINT32        NewValue;

  //
  // Get PM1BLK_Base & GPE0BLK_Base
  //
  PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress);
  GPE0BLK_Base = (UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF);


  //
  // Enable APM SMI
  //
  IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIE), B_QNC_GPE0BLK_SMIE_APM);

  //
  // Enable SMI globally
  //
  NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
  NewValue |= SMI_EN;
  QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);

  //
  // Set APM_STS
  //
  IoWrite8 (PcdGet16 (PcdSmmDataPort), Data);

  //
  // Generate the APM SMI
  //
  IoWrite8 (PcdGet16 (PcdSmmActivationPort), PcdGet8 (PcdSmmActivationData));

  //
  // Clear the APM SMI Status Bit
  //
  IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM);

  //
  // Set the EOS Bit
  //
  IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);
}
Example #4
0
/**
  Calling this function causes the system to enter a power state for capsule
  update.

  Reset update should not return, if it returns, it means the system does
  not support capsule update.

**/
VOID
EFIAPI
EnterS3WithImmediateWake (
VOID
)
{
  UINT8     Data8;
  UINT16    Data16;
  UINT32    Data32;
  UINTN     Eflags;
  UINTN     RegCr0;
  EFI_TIME  EfiTime;
  UINT32    SmiEnSave;

  Eflags  = AsmReadEflags ();
  if ( (Eflags & 0x200) ) {
     DisableInterrupts ();
  }

  //
  //  Write all cache data to memory because processor will lost power
  //
  AsmWbinvd();
  RegCr0 = AsmReadCr0();
  AsmWriteCr0 (RegCr0 | 0x060000000);

  SmiEnSave = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
  QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, (SmiEnSave & ~SMI_EN));

  //
  // Pogram RTC alarm for immediate WAKE
  //

  //
  // Disable SMI sources
  //
  IoWrite16 (PcdGet16 (PcdGpe0blkIoBaseAddress) + R_QNC_GPE0BLK_SMIE, 0);

  //
  // Disable RTC alarm interrupt
  //
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B);
  Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
  IoWrite8 (PCAT_RTC_DATA_REGISTER, (Data8 & ~BIT5));

  //
  // Clear RTC alarm if already set
  //
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_C);
  Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);              // Read clears alarm status

  //
  // Disable all WAKE events
  //
  IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, B_QNC_PM1BLK_PM1E_PWAKED);

  //
  // Clear all WAKE status bits
  //
  IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S, B_QNC_PM1BLK_PM1S_ALL);

  //
  // Avoid RTC rollover
  //
  do {
    WaitForRTCUpdate();
    IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS);
    EfiTime.Second = IoRead8 (PCAT_RTC_DATA_REGISTER);
  } while (EfiTime.Second > PLATFORM_RTC_ROLLOVER_LIMIT);

  //
  // Read RTC time
  //
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOURS);
  EfiTime.Hour = IoRead8 (PCAT_RTC_DATA_REGISTER);
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTES);
  EfiTime.Minute = IoRead8 (PCAT_RTC_DATA_REGISTER);
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS);
  EfiTime.Second = IoRead8 (PCAT_RTC_DATA_REGISTER);

  //
  // Set RTC alarm
  //

  //
  // Add PLATFORM_WAKE_SECONDS_BUFFER to current EfiTime.Second
  // The maths is to allow for the fact we are adding to a BCD number and require the answer to be BCD (EfiTime.Second)
  //
  if ((BCD_BASE - (EfiTime.Second & 0x0F)) <= PLATFORM_WAKE_SECONDS_BUFFER) {
    Data8 = (((EfiTime.Second & 0xF0) + 0x10) + (PLATFORM_WAKE_SECONDS_BUFFER - (BCD_BASE - (EfiTime.Second & 0x0F))));
  } else {
    Data8 = EfiTime.Second + PLATFORM_WAKE_SECONDS_BUFFER;
  }

  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOURS_ALARM);
  IoWrite8 (PCAT_RTC_DATA_REGISTER, EfiTime.Hour);
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTES_ALARM);
  IoWrite8 (PCAT_RTC_DATA_REGISTER, EfiTime.Minute);
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS_ALARM);
  IoWrite8 (PCAT_RTC_DATA_REGISTER, Data8);

  //
  // Enable RTC alarm interrupt
  //
  IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B);
  Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
  IoWrite8 (PCAT_RTC_DATA_REGISTER, (Data8 | BIT5));

  //
  // Enable RTC alarm as WAKE event
  //
  Data16 = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E);
  IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, (Data16 | B_QNC_PM1BLK_PM1E_RTC));

  //
  // Enter S3
  //
  Data32 = IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
  Data32  = (UINT32) ((Data32 & 0xffffc3fe) | V_S3 | B_QNC_PM1BLK_PM1C_SCIEN);
  IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Data32);
  Data32 = Data32 | B_QNC_PM1BLK_PM1C_SLPEN;
  IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Data32);

  //
  // Enable Interrupt if it's enabled before
  //
  if ( (Eflags & 0x200) ) {
     EnableInterrupts ();
  }
}
Example #5
0
/**
  This function will be called when MRC is done.

  @param  PeiServices General purpose services available to every PEIM.

  @param  NotifyDescriptor Information about the notify event..

  @param  Ppi The notify context.

  @retval EFI_SUCCESS If the function completed successfully.
**/
EFI_STATUS
EFIAPI
MemoryDiscoveredPpiNotifyCallback (
  IN EFI_PEI_SERVICES           **PeiServices,
  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
  IN VOID                       *Ppi
  )
{
  EFI_STATUS                            Status;
  EFI_BOOT_MODE                         BootMode;
  UINT64                                MemoryLength;
  UINT64                                MemoryLengthUc;
  UINT64                                MaxMemoryLength;
  UINT64                                MemOverflow;
  EFI_SMRAM_DESCRIPTOR                  *SmramDescriptor;
  UINTN                                 NumSmramRegions;
  UINT64                                EnlargedMemoryLength;
  UINT32                                RmuMainBaseAddress;
  UINTN                                 Index;
  MTRR_SETTINGS                         MtrrSetting;
  UINT32                                RegData32;
  EFI_PHYSICAL_ADDRESS                  NewBuffer;
  UINT8                                 CpuAddressWidth;
  EFI_CPUID_REGISTER                    FeatureInfo;
  
  DEBUG ((EFI_D_INFO, "Platform PEIM Memory Callback\n"));

  NumSmramRegions = 0;
  SmramDescriptor = NULL;
  RmuMainBaseAddress = 0;

  PERF_START (NULL, "SetCache", NULL, 0);

  InfoPostInstallMemory (&RmuMainBaseAddress, &SmramDescriptor, &NumSmramRegions);
  ASSERT (SmramDescriptor != NULL);
  ASSERT (RmuMainBaseAddress != 0);

  MemoryLength = ((UINT64) RmuMainBaseAddress) + 0x10000;
  EnlargedMemoryLength = MemoryLength;

  if (NumSmramRegions > 0) {
	  //
	  // Find the TSEG
	  //
	  for (Index = 0; Index < NumSmramRegions; Index ++) {
	    if ((SmramDescriptor[Index].PhysicalStart) == EnlargedMemoryLength) {
	      if (SmramDescriptor[Index].RegionState & EFI_CACHEABLE) {
	        //
	        // Enlarge memory length to include TSEG size
	        //
	        EnlargedMemoryLength += (SmramDescriptor[Index].PhysicalSize);
	      }
	    }
	  }
	}

  //
  // Check if a UC region is present
  //
  MaxMemoryLength = EnlargedMemoryLength;
  // Round up to nearest 256MB
  MemOverflow = (MemoryLength & 0x0fffffff);
  if (MemOverflow != 0) {
    MaxMemoryLength = MemoryLength + (0x10000000 - MemOverflow);
  }


  Status = PeiServicesGetBootMode (&BootMode);
  ASSERT_EFI_ERROR (Status);

  ZeroMem (&MtrrSetting, sizeof(MTRR_SETTINGS));
  (**PeiServices).CopyMem ((VOID *)&MtrrSetting.Fixed,(VOID *)&mFixedMtrrTable, sizeof(MTRR_FIXED_SETTINGS) );
  //
  // Cache the flash area to improve the boot performance in PEI phase
  //
  MtrrSetting.Variables.Mtrr[0].Base = (QUARK_BOOTROM_BASE_ADDRESS | CacheWriteBack);  
  MtrrSetting.Variables.Mtrr[0].Mask = (((~(QUARK_BOOTROM_SIZE_BYTES - 1)) & MTRR_LIB_CACHE_VALID_ADDRESS) | MTRR_LIB_CACHE_MTRR_ENABLED);
  
  MtrrSetting.Variables.Mtrr[1].Base = CacheWriteBack;  
  MtrrSetting.Variables.Mtrr[1].Mask = ((~(MaxMemoryLength - 1)) & MTRR_LIB_CACHE_VALID_ADDRESS) | MTRR_LIB_CACHE_MTRR_ENABLED;

  Index = 2;
  while (MaxMemoryLength != MemoryLength) {
    MemoryLengthUc = GetPowerOfTwo64 (MaxMemoryLength - MemoryLength);

    //Status = MtrrSetMemoryAttribute (MaxMemoryLength - MemoryLengthUc, MemoryLengthUc, CacheUncacheable);
    //ASSERT_EFI_ERROR (Status);
    
    MtrrSetting.Variables.Mtrr[Index].Base = ((MaxMemoryLength - MemoryLengthUc) & MTRR_LIB_CACHE_VALID_ADDRESS) | CacheUncacheable;
    MtrrSetting.Variables.Mtrr[Index].Mask= ((~(MemoryLengthUc   - 1)) & MTRR_LIB_CACHE_VALID_ADDRESS) | MTRR_LIB_CACHE_MTRR_ENABLED;      
    MaxMemoryLength -= MemoryLengthUc;
    Index++;
  }

  AsmInvd ();
 
  MtrrSetting.MtrrDefType = MTRR_LIB_CACHE_MTRR_ENABLED | MTRR_LIB_CACHE_FIXED_MTRR_ENABLED;
  MtrrSetAllMtrrs(&MtrrSetting);

  PERF_END (NULL, "SetCache", NULL, 0);

  //
  // Install PeiReset for PeiResetSystem service
  //
  Status = PeiServicesInstallPpi (&mPpiList[0]);
  ASSERT_EFI_ERROR (Status);

  //
  // Do QNC initialization after MRC
  //
  PeiQNCPostMemInit ();

  Status = PeiServicesInstallPpi (&mPpiStall[0]);
  ASSERT_EFI_ERROR (Status);

  //
  // Set E000/F000 Routing
  //
  RegData32 = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
  RegData32 |= (BIT2|BIT1);
  QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, RegData32);

  if (BootMode == BOOT_IN_RECOVERY_MODE) {
  PeiServicesInstallFvInfoPpi (
    NULL,
    (VOID *) (UINTN) PcdGet32 (PcdFlashFvRecovery2Base),
    PcdGet32 (PcdFlashFvRecovery2Size),
    NULL,
    NULL
    );
    Status = PeimInitializeRecovery (PeiServices);
    ASSERT_EFI_ERROR (Status);

  } else if (BootMode == BOOT_ON_S3_RESUME) {
    return EFI_SUCCESS;

  } else {
    //
    // Allocate the memory so that it gets preserved into DXE
    //
    Status = PeiServicesAllocatePages (
              EfiBootServicesData,
              EFI_SIZE_TO_PAGES (PcdGet32 (PcdFvSecurityHeaderSize) + PcdGet32 (PcdFlashFvMainSize)),
              &NewBuffer
              );

    //
    // Copy the compressed main Firmware Volume to memory for faster processing later
    //
    CopyMem ((VOID *) (UINTN) NewBuffer, (VOID *) (UINTN) (PcdGet32 (PcdFlashFvMainBase) - PcdGet32 (PcdFvSecurityHeaderSize)), (PcdGet32 (PcdFvSecurityHeaderSize) +PcdGet32 (PcdFlashFvMainSize)));

    PeiServicesInstallFvInfoPpi (
      NULL,
      (VOID *) (UINTN) (NewBuffer + PcdGet32 (PcdFvSecurityHeaderSize)),
      PcdGet32 (PcdFlashFvMainSize),
      NULL,
      NULL
      );
  }

  //
  // Build flash HOB, it's going to be used by GCD and E820 building
  // Map full SPI flash decode range (regardless of smaller SPI flash parts installed)
  //
  BuildResourceDescriptorHob (
    EFI_RESOURCE_FIRMWARE_DEVICE,
    (EFI_RESOURCE_ATTRIBUTE_PRESENT    |
    EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
    EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE),
    (SIZE_4GB - SIZE_8MB),
    SIZE_8MB
    );

  //
  // Create a CPU hand-off information
  //
  CpuAddressWidth = 32;
  AsmCpuid (EFI_CPUID_EXTENDED_FUNCTION, &FeatureInfo.RegEax, NULL, NULL, NULL);
  if (FeatureInfo.RegEax >= EFI_CPUID_VIR_PHY_ADDRESS_SIZE) {
    AsmCpuid (EFI_CPUID_VIR_PHY_ADDRESS_SIZE, &FeatureInfo.RegEax, NULL, NULL, NULL);
    CpuAddressWidth = (UINT8) (FeatureInfo.RegEax & 0xFF);
  }
  DEBUG ((EFI_D_INFO, "CpuAddressWidth: %d\n", CpuAddressWidth));

  BuildCpuHob (CpuAddressWidth, 16);

  ASSERT_EFI_ERROR (Status);

  return Status;
}
Example #6
0
/**
  This function will be called when MRC is done.

  @param  PeiServices General purpose services available to every PEIM.

  @param  NotifyDescriptor Information about the notify event..

  @param  Ppi The notify context.

  @retval EFI_SUCCESS If the function completed successfully.
**/
EFI_STATUS
EFIAPI
MemoryDiscoveredPpiNotifyCallback (
  IN EFI_PEI_SERVICES           **PeiServices,
  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
  IN VOID                       *Ppi
  )
{
  EFI_STATUS                            Status;
  EFI_BOOT_MODE                         BootMode;
  UINT64                                MemoryLength;
  EFI_SMRAM_DESCRIPTOR                  *SmramDescriptor;
  UINTN                                 NumSmramRegions;
  UINT32                                RmuMainBaseAddress;
  UINT32                                RegData32;
  UINT8                                 CpuAddressWidth;
  UINT32                                RegEax;
  MTRR_SETTINGS                         MtrrSettings;
  EFI_PEI_READ_ONLY_VARIABLE2_PPI       *VariableServices;
  UINT8                                 MorControl;
  UINTN                                 DataSize;

  DEBUG ((EFI_D_INFO, "Platform PEIM Memory Callback\n"));

  NumSmramRegions = 0;
  SmramDescriptor = NULL;
  RmuMainBaseAddress = 0;

  PERF_START (NULL, "SetCache", NULL, 0);

  InfoPostInstallMemory (&RmuMainBaseAddress, &SmramDescriptor, &NumSmramRegions);
  ASSERT (SmramDescriptor != NULL);
  ASSERT (RmuMainBaseAddress != 0);

  MemoryLength = ((UINT64) RmuMainBaseAddress) + 0x10000;

  Status = PeiServicesGetBootMode (&BootMode);
  ASSERT_EFI_ERROR (Status);

  //
  // Get current MTRR settings
  //
  MtrrGetAllMtrrs (&MtrrSettings);

  //
  // Set all DRAM cachability to CacheWriteBack
  //
  Status = MtrrSetMemoryAttributeInMtrrSettings (&MtrrSettings, 0, MemoryLength, CacheWriteBack);
  ASSERT_EFI_ERROR (Status);

  //
  // RTC:28208 - System hang/crash when entering probe mode(ITP) when relocating SMBASE
  //             Workaround to make default SMRAM UnCachable
  //
  Status = MtrrSetMemoryAttributeInMtrrSettings (&MtrrSettings, 0x30000, SIZE_64KB, CacheUncacheable);
  ASSERT_EFI_ERROR (Status);

  //
  // Set new MTRR settings
  //
  MtrrSetAllMtrrs (&MtrrSettings);

  PERF_END (NULL, "SetCache", NULL, 0);

  //
  // Get necessary PPI
  //
  Status = PeiServicesLocatePpi (
             &gEfiPeiReadOnlyVariable2PpiGuid,           // GUID
             0,                                          // INSTANCE
             NULL,                                       // EFI_PEI_PPI_DESCRIPTOR
             (VOID **)&VariableServices                  // PPI
             );
  ASSERT_EFI_ERROR (Status);

  //
  // Detect MOR request by the OS.
  //
  MorControl = 0;
  DataSize = sizeof (MorControl);
  Status = VariableServices->GetVariable (
                               VariableServices,
                               MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
                               &gEfiMemoryOverwriteControlDataGuid,
                               NULL,
                               &DataSize,
                               &MorControl
                               );
  //
  // If OS requested a memory overwrite perform it now for Embedded SRAM
  //
  if (MOR_CLEAR_MEMORY_VALUE (MorControl)) {
    DEBUG ((EFI_D_INFO, "Clear Embedded SRAM per MOR request.\n"));
    if (PcdGet32 (PcdESramMemorySize) > 0) {
      if (PcdGet32 (PcdEsramStage1Base) == 0) {
        //
        // ZeroMem() generates an ASSERT() if Buffer parameter is NULL.
        // Clear byte at 0 and start clear operation at address 1.
        //
        *(UINT8 *)(0) = 0;
        ZeroMem ((VOID *)1, (UINTN)PcdGet32 (PcdESramMemorySize) - 1);
      } else {
        ZeroMem (
          (VOID *)(UINTN)PcdGet32 (PcdEsramStage1Base),
          (UINTN)PcdGet32 (PcdESramMemorySize)
          );
      }
    }
  }

  //
  // Install PeiReset for PeiResetSystem service
  //
  Status = PeiServicesInstallPpi (&mPpiList[0]);
  ASSERT_EFI_ERROR (Status);

  //
  // Do QNC initialization after MRC
  //
  PeiQNCPostMemInit ();

  Status = PeiServicesInstallPpi (&mPpiStall[0]);
  ASSERT_EFI_ERROR (Status);

  //
  // Set E000/F000 Routing
  //
  RegData32 = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
  RegData32 |= (BIT2|BIT1);
  QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, RegData32);

  if (BootMode == BOOT_IN_RECOVERY_MODE) {
    // Do nothing here. A generic RecoveryModule will handle it.
  } else if (BootMode == BOOT_ON_S3_RESUME) {
    return EFI_SUCCESS;
  } else {
    PeiServicesInstallFvInfoPpi (
      NULL,
      (VOID *) (UINTN) PcdGet32 (PcdFlashFvMainBase),
      PcdGet32 (PcdFlashFvMainSize),
      NULL,
      NULL
      );

    //
    // Publish the FVMAIN FV so the DXE Phase can dispatch drivers from this FV
    // and produce Load File Protocols for UEFI Applications in this FV.
    //
    BuildFvHob (
      PcdGet32 (PcdFlashFvMainBase),
      PcdGet32 (PcdFlashFvMainSize)
      );

    //
    // Publish the Payload FV so the DXE Phase can dispatch drivers from this FV
    // and produce Load File Protocols for UEFI Applications in this FV.
    //
    BuildFvHob (
      PcdGet32 (PcdFlashFvPayloadBase),
      PcdGet32 (PcdFlashFvPayloadSize)
      );
  }

  //
  // Build flash HOB, it's going to be used by GCD and E820 building
  // Map full SPI flash decode range (regardless of smaller SPI flash parts installed)
  //
  BuildResourceDescriptorHob (
    EFI_RESOURCE_FIRMWARE_DEVICE,
    (EFI_RESOURCE_ATTRIBUTE_PRESENT    |
    EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
    EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE),
    (SIZE_4GB - SIZE_8MB),
    SIZE_8MB
    );

  //
  // Create a CPU hand-off information
  //
  CpuAddressWidth = 32;
  AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);
  if (RegEax >= CPUID_VIR_PHY_ADDRESS_SIZE) {
    AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &RegEax, NULL, NULL, NULL);
    CpuAddressWidth = (UINT8) (RegEax & 0xFF);
  }
  DEBUG ((EFI_D_INFO, "CpuAddressWidth: %d\n", CpuAddressWidth));

  BuildCpuHob (CpuAddressWidth, 16);

  ASSERT_EFI_ERROR (Status);

  return Status;
}
Example #7
0
/**
  This function is the main entry point for an SMM handler dispatch
  or communicate-based callback.

  @param  DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().
  @param  RegisterContext Points to an optional handler context which was specified when the handler was registered.
  @param  CommBuffer      A pointer to a collection of data in memory that will
                          be conveyed from a non-SMM environment into an SMM environment.
  @param  CommBufferSize  The size of the CommBuffer.

  @return Status Code

**/
EFI_STATUS
QNCSmmCoreDispatcher (
  IN     EFI_HANDLE               DispatchHandle,
  IN     CONST VOID               *RegisterContext,
  IN OUT VOID                     *CommBuffer,
  IN OUT UINTN                    *CommBufferSize
  )
{
  //
  // Used to prevent infinite loops
  //
  UINTN               EscapeCount;

  BOOLEAN             ContextsMatch;
  BOOLEAN             ResetListSearch;
  BOOLEAN             EosSet;
  BOOLEAN             SxChildWasDispatched;
  BOOLEAN             ChildWasDispatched;

  DATABASE_RECORD     *RecordInDb;
  DATABASE_RECORD     ActiveRecordInDb;
  LIST_ENTRY          *LinkInDb;
  DATABASE_RECORD     *RecordToExhaust;
  LIST_ENTRY          *LinkToExhaust;

  QNC_SMM_CONTEXT     Context;
  VOID                *CommunicationBuffer;
  UINTN               BufferSize;

  EFI_STATUS          Status;
  UINT32              NewValue;

  QNC_SMM_SOURCE_DESC ActiveSource = NULL_SOURCE_DESC_INITIALIZER;

  EscapeCount           = 100;
  ContextsMatch         = FALSE;
  ResetListSearch       = FALSE;
  EosSet                = FALSE;
  SxChildWasDispatched  = FALSE;
  Status                = EFI_WARN_INTERRUPT_SOURCE_PENDING;
  ChildWasDispatched    = FALSE;

  //
  // Mark all child handlers as not processed
  //
  LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
  while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
    RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
    RecordInDb->Processed = FALSE;
    LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, LinkInDb);
  }

  //
  // Preserve Index registers
  //
  SaveState ();

  if (!IsListEmpty (&mPrivateData.CallbackDataBase)) {
    //
    // We have children registered w/ us -- continue
    //
    while ((!EosSet) && (EscapeCount > 0)) {
      EscapeCount--;

      //
      // Reset this flag in order to be able to process multiple SMI Sources in one loop.
      //
      ResetListSearch = FALSE;

      LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);

      while ((!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) && (ResetListSearch == FALSE)) {
        RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
        //
        // Make a copy of the record that contains an active SMI source,
        // because un-register maybe invoked in callback function and
        // RecordInDb maybe released
        //
        CopyMem (&ActiveRecordInDb, RecordInDb, sizeof (ActiveRecordInDb));

        //
        // look for the first active source
        //
        if (!SourceIsActive (&RecordInDb->SrcDesc)) {
          //
          // Didn't find the source yet, keep looking
          //
          LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);

        } else {
          //
          // We found a source. If this is a sleep type, we have to go to
          // appropriate sleep state anyway.No matter there is sleep child or not
          //
          if (RecordInDb->ProtocolType == SxType) {
            SxChildWasDispatched = TRUE;
          }
          //
          // "cache" the source description and don't query I/O anymore
          //
          CopyMem (&ActiveSource, &RecordInDb->SrcDesc, sizeof (ActiveSource));
          LinkToExhaust = LinkInDb;

          //
          // exhaust the rest of the queue looking for the same source
          //
          while (!IsNull (&mPrivateData.CallbackDataBase, LinkToExhaust)) {
            RecordToExhaust = DATABASE_RECORD_FROM_LINK (LinkToExhaust);
            LinkToExhaust = GetNextNode (&mPrivateData.CallbackDataBase, LinkToExhaust);
            if (RecordToExhaust->Processed) {
              //
              // Record has already been processed.  Continue with next child handler.
              //
              continue;
            }

            if (CompareSources (&RecordToExhaust->SrcDesc, &ActiveSource)) {
              //
              // These source descriptions are equal, so this callback should be
              // dispatched.
              //
              if (RecordToExhaust->ContextFunctions.GetContext != NULL) {
                //
                // This child requires that we get a calling context from
                // hardware and compare that context to the one supplied
                // by the child.
                //
                ASSERT (RecordToExhaust->ContextFunctions.CmpContext != NULL);

                //
                // Make sure contexts match before dispatching event to child
                //
                RecordToExhaust->ContextFunctions.GetContext (RecordToExhaust, &Context);
                ContextsMatch = RecordToExhaust->ContextFunctions.CmpContext (&Context, &RecordToExhaust->ChildContext);

              } else {
                //
                // This child doesn't require any more calling context beyond what
                // it supplied in registration.  Simply pass back what it gave us.
                //
                ASSERT (RecordToExhaust->Callback != NULL);
                ContextsMatch = TRUE;
              }

              //
              // Mark this child handler so it will not be processed again
              //
              RecordToExhaust->Processed = TRUE;

              if (ContextsMatch) {

                if (RecordToExhaust->BufferSize != 0) {
                  ASSERT (RecordToExhaust->ContextFunctions.GetBuffer != NULL);

                  RecordToExhaust->ContextFunctions.GetBuffer (RecordToExhaust);

                  CommunicationBuffer = &RecordToExhaust->CommBuffer;
                  BufferSize = RecordToExhaust->BufferSize;
                } else {
                  CommunicationBuffer = NULL;
                  BufferSize = 0;
                }

                ASSERT (RecordToExhaust->Callback != NULL);

                RecordToExhaust->Callback (
                                   (EFI_HANDLE) & RecordToExhaust->Link,
                                   RecordToExhaust->CallbackContext,
                                   CommunicationBuffer,
                                   &BufferSize
                                   );

                ChildWasDispatched = TRUE;
                if (RecordToExhaust->ProtocolType == SxType) {
                  SxChildWasDispatched = TRUE;
                }
              }
              //
              // Can not use RecordInDb after this point because Callback may have unregistered RecordInDb
              // Restart processing of SMI handlers from the begining of the linked list because the
              // state of the linked listed may have been modified due to unregister actions in the Callback.
              //
              LinkToExhaust = GetFirstNode (&mPrivateData.CallbackDataBase);
            }
          }

          if (ActiveRecordInDb.ClearSource == NULL) {
            //
            // Clear the SMI associated w/ the source using the default function
            //
            QNCSmmClearSource (&ActiveSource);
          } else {
            //
            // This source requires special handling to clear
            //
            ActiveRecordInDb.ClearSource (&ActiveSource);
          }

          if (ChildWasDispatched) {
            //
            // The interrupt was handled and quiesced
            //
            Status = EFI_SUCCESS;
          } else {
            //
            // The interrupt was not handled but quiesced
            //
            Status = EFI_WARN_INTERRUPT_SOURCE_QUIESCED;
          }

          //
          // Queue is empty, reset the search
          //
          ResetListSearch = TRUE;

        }
      }
      EosSet = QNCSmmSetAndCheckEos ();
    }
  }
  //
  // If you arrive here, there are two possible reasons:
  // (1) you've got problems with clearing the SMI status bits in the
  // ACPI table.  If you don't properly clear the SMI bits, then you won't be able to set the
  // EOS bit.  If this happens too many times, the loop exits.
  // (2) there was a SMM communicate for callback messages that was received prior
  // to this driver.
  // If there is an asynchronous SMI that occurs while processing the Callback, let
  // all of the drivers (including this one) have an opportunity to scan for the SMI
  // and handle it.
  // If not, we don't want to exit and have the foreground app. clear EOS without letting
  // these other sources get serviced.
  //
  ASSERT (EscapeCount > 0);

  //
  // Restore Index registers
  //
  RestoreState ();

  if (SxChildWasDispatched) {
    //
    // A child of the SmmSxDispatch protocol was dispatched during this call;
    // put the system to sleep.
    //
    QNCSmmSxGoToSleep ();
  }

  //
  // Ensure that SMI signal pin indicator is clear at the end of SMM handling.
  //
  NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HLEGACY_REG);
  NewValue &= ~(HLEGACY_SMI_PIN_VALUE);
  QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HLEGACY_REG, NewValue);

  return Status;
}
Example #8
0
VOID
EFIAPI
PlatformConfigOnSmmConfigurationProtocol (
  IN  EFI_EVENT Event,
  IN  VOID      *Context
  )
/*++

Routine Description:

  Function runs in PI-DXE to perform platform specific config when
  SmmConfigurationProtocol is installed.

Arguments:
  Event       - The event that occured.
  Context     - For EFI compatiblity.  Not used.

Returns:
  None.
--*/

{
  EFI_STATUS            Status;
  UINT32                NewValue;
  UINT64                BaseAddress;
  UINT64                SmramLength;
  EFI_CPU_ARCH_PROTOCOL *CpuArchProtocol;   // RTC:28208 - System hang/crash when entering probe mode(ITP) when relocating SMBASE
  VOID                  *SmmCfgProt;

  Status = gBS->LocateProtocol (&gEfiSmmConfigurationProtocolGuid, NULL, &SmmCfgProt);
  if (Status != EFI_SUCCESS){
    DEBUG ((DEBUG_INFO, "gEfiSmmConfigurationProtocolGuid triggered but not valid.\n"));
    return;
  }
  if (mMemCfgDone) {
    DEBUG ((DEBUG_INFO, "Platform DXE Mem config already done.\n"));
    return;
  }

  //
  // Disable eSram block (this will also clear/zero eSRAM)
  // We only use eSRAM in the PEI phase. Disable now that we are in the DXE phase
  //
  NewValue = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_ESRAMPGCTRL_BLOCK);
  NewValue |= BLOCK_DISABLE_PG;
  QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_ESRAMPGCTRL_BLOCK, NewValue);

  //
  // Update HMBOUND to top of DDR3 memory and LOCK
  // We disabled eSRAM so now we move HMBOUND down to top of DDR3
  //
  QNCGetTSEGMemoryRange (&BaseAddress, &SmramLength);
  NewValue = (UINT32)(BaseAddress + SmramLength);
  DEBUG ((EFI_D_INFO,"Locking HMBOUND at: = 0x%8x\n",NewValue));
  QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HMBOUND_REG, (NewValue | HMBOUND_LOCK));

  if(FeaturePcdGet (PcdEnableSecureLock)) {
    //
    // Lock IMR5 now that HMBOUND is locked (legacy S3 region)
    //
    NewValue = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR5+QUARK_NC_MEMORY_MANAGER_IMRXL);
    NewValue |= IMR_LOCK;
    QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR5+QUARK_NC_MEMORY_MANAGER_IMRXL, NewValue);

    //
    // Lock IMR6 now that HMBOUND is locked (ACPI Reclaim/ACPI/Runtime services/Reserved)
    //
    NewValue = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR6+QUARK_NC_MEMORY_MANAGER_IMRXL);
    NewValue |= IMR_LOCK;
    QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR6+QUARK_NC_MEMORY_MANAGER_IMRXL, NewValue);

    //
    // Disable IMR2 memory protection (RMU Main Binary)
    //
    QncImrWrite (
              QUARK_NC_MEMORY_MANAGER_IMR2,
              (UINT32)(IMRL_RESET & ~IMR_EN),
              (UINT32)IMRH_RESET,
              (UINT32)IMRX_ALL_ACCESS,
              (UINT32)IMRX_ALL_ACCESS
          );

    //
    // Disable IMR3 memory protection (Default SMRAM)
    //
    QncImrWrite (
              QUARK_NC_MEMORY_MANAGER_IMR3,
              (UINT32)(IMRL_RESET & ~IMR_EN),
              (UINT32)IMRH_RESET,
              (UINT32)IMRX_ALL_ACCESS,
              (UINT32)IMRX_ALL_ACCESS
          );

    //
    // Disable IMR4 memory protection (eSRAM).
    //
    QncImrWrite (
              QUARK_NC_MEMORY_MANAGER_IMR4,
              (UINT32)(IMRL_RESET & ~IMR_EN),
              (UINT32)IMRH_RESET,
              (UINT32)IMRX_ALL_ACCESS,
              (UINT32)IMRX_ALL_ACCESS
          );
  }

  //
  // RTC:28208 - System hang/crash when entering probe mode(ITP) when relocating SMBASE
  //             Workaround to make default SMRAM UnCachable
  //
  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &CpuArchProtocol);
  ASSERT_EFI_ERROR (Status);

  CpuArchProtocol->SetMemoryAttributes (
                     CpuArchProtocol,
                     (EFI_PHYSICAL_ADDRESS) SMM_DEFAULT_SMBASE,
                     SMM_DEFAULT_SMBASE_SIZE_BYTES,
                     EFI_MEMORY_WB
                     );

  mMemCfgDone = TRUE;
}
Example #9
0
EFI_STATUS
EFIAPI
SpiProtocolExecute (
  IN     EFI_SPI_PROTOCOL   *This,
  IN     UINT8              OpcodeIndex,
  IN     UINT8              PrefixOpcodeIndex,
  IN     BOOLEAN            DataCycle,
  IN     BOOLEAN            Atomic,
  IN     BOOLEAN            ShiftOut,
  IN     UINTN              Address,
  IN     UINT32             DataByteCount,
  IN OUT UINT8              *Buffer,
  IN     SPI_REGION_TYPE    SpiRegionType
  )
/*++

Routine Description:

  Execute SPI commands from the host controller.
  This function would be called by runtime driver, please do not use any MMIO marco here

Arguments:

  This              Pointer to the EFI_SPI_PROTOCOL instance.
  OpcodeIndex       Index of the command in the OpCode Menu.
  PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence.
  DataCycle         TRUE if the SPI cycle contains data
  Atomic            TRUE if the SPI cycle is atomic and interleave cycles are not allowed.
  ShiftOut          If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in.
  Address           In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform
                    Region, this value specifies the offset from the Region Base; for BIOS Region,
                    this value specifies the offset from the start of the BIOS Image. In Non
                    Descriptor Mode, this value specifies the offset from the start of the BIOS Image.
                    Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor
                    Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is
                    supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or
                    the flash (in Non Descriptor Mode)
  DataByteCount     Number of bytes in the data portion of the SPI cycle. This function may break the
                    data transfer into multiple operations. This function ensures each operation does
                    not cross 256 byte flash address boundary.
                    *NOTE: if there is some SPI chip that has a stricter address boundary requirement
                    (e.g., its write page size is < 256 byte), then the caller cannot rely on this
                    function to cut the data transfer at proper address boundaries, and it's the
                    caller's reponsibility to pass in a properly cut DataByteCount parameter.
  Buffer            Pointer to caller-allocated buffer containing the dada received or sent during the
                    SPI cycle.
  SpiRegionType     SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,
                    EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in
                    Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode
                    and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative
                    to base of the 1st flash device (i.e., it is a Flash Linear Address).

Returns:

  EFI_SUCCESS             Command succeed.
  EFI_INVALID_PARAMETER   The parameters specified are not valid.
  EFI_UNSUPPORTED         Command not supported.
  EFI_DEVICE_ERROR        Device error, command aborts abnormally.

--*/
{
  EFI_STATUS  Status;
  UINT16      BiosCtlSave;
  UINT32      SmiEnSave;

  BiosCtlSave = 0;
  SmiEnSave   = 0;

  //
  // Check if the parameters are valid.
  //
  if ((OpcodeIndex >= SPI_NUM_OPCODE) || (PrefixOpcodeIndex >= SPI_NUM_PREFIX_OPCODE)) {
    return EFI_INVALID_PARAMETER;
  }
  //
  // Make sure it's safe to program the command.
  //
  if (!WaitForSpiCycleComplete (This, FALSE)) {
    return EFI_DEVICE_ERROR;
  }

  //
  // Acquire access to the SPI interface is not required any more.
  //
  //
  // Disable SMIs to make sure normal mode flash access is not interrupted by an SMI
  // whose SMI handler accesses flash (e.g. for error logging)
  //
  SmiEnSave = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
  QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, (SmiEnSave & ~SMI_EN));

  //
  // Save BIOS Ctrl register
  //
  BiosCtlSave = PciRead16 (
                  PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC,
                  PCI_DEVICE_NUMBER_QNC_LPC,
                  PCI_FUNCTION_NUMBER_QNC_LPC,
                  R_QNC_LPC_BIOS_CNTL)
                  ) & (B_QNC_LPC_BIOS_CNTL_BCD | B_QNC_LPC_BIOS_CNTL_PFE | B_QNC_LPC_BIOS_CNTL_BIOSWE | B_QNC_LPC_BIOS_CNTL_SMM_BWP);

  //
  // Enable flash writing
  //
  PciOr16 (
    PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC,
    PCI_DEVICE_NUMBER_QNC_LPC,
    PCI_FUNCTION_NUMBER_QNC_LPC,
    R_QNC_LPC_BIOS_CNTL),
    (UINT16) (B_QNC_LPC_BIOS_CNTL_BIOSWE | B_QNC_LPC_BIOS_CNTL_SMM_BWP)
    );

  //
  // If shifts the data out, disable Prefetching and Caching.
  //
  if (ShiftOut) {
    PciAndThenOr16 (
      PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC,
      PCI_DEVICE_NUMBER_QNC_LPC,
      PCI_FUNCTION_NUMBER_QNC_LPC,
      R_QNC_LPC_BIOS_CNTL),
      (UINT16) (~(B_QNC_LPC_BIOS_CNTL_BCD | B_QNC_LPC_BIOS_CNTL_PFE)),
      (UINT16) ((B_QNC_LPC_BIOS_CNTL_BCD))
      );
  }
  //
  // Sends the command to the SPI interface to execute.
  //
  Status = SendSpiCmd (
            This,
            OpcodeIndex,
            PrefixOpcodeIndex,
            DataCycle,
            Atomic,
            ShiftOut,
            Address,
            DataByteCount,
            Buffer,
            SpiRegionType
            );

  //
  // Restore BIOS Ctrl register
  //
  PciAndThenOr16 (
    PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC,
    PCI_DEVICE_NUMBER_QNC_LPC,
    PCI_FUNCTION_NUMBER_QNC_LPC,
    R_QNC_LPC_BIOS_CNTL),
    (UINT16) (~(B_QNC_LPC_BIOS_CNTL_BCD | B_QNC_LPC_BIOS_CNTL_PFE | B_QNC_LPC_BIOS_CNTL_BIOSWE | B_QNC_LPC_BIOS_CNTL_SMM_BWP)),
    (UINT16) (BiosCtlSave)
      );
  //
  // Restore SMIs.
  //
  QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, SmiEnSave);

  return Status;
}