Home | History | Annotate | Download | only in PlatformInit
      1 /** @file
      2 This file provide the function to detect boot mode
      3 
      4 Copyright (c) 2013 Intel Corporation.
      5 
      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 
     17 #include "CommonHeader.h"
     18 #include <Pi/PiFirmwareVolume.h>
     19 
     20 EFI_PEI_PPI_DESCRIPTOR mPpiListRecoveryBootMode = {
     21   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
     22   &gEfiPeiBootInRecoveryModePpiGuid,
     23   NULL
     24 };
     25 
     26 /**
     27   If the box was opened, it's boot with full config.
     28   If the box is closed, then
     29     1. If it's first time to boot, it's boot with full config .
     30     2. If the ChassisIntrution is selected, force to be a boot with full config
     31     3. Otherwise it's boot with no change.
     32 
     33   @param  PeiServices General purpose services available to every PEIM.
     34 
     35   @retval TRUE  If it's boot with no change.
     36 
     37   @retval FALSE If boot with no change.
     38 **/
     39 BOOLEAN
     40 IsBootWithNoChange (
     41   IN EFI_PEI_SERVICES   **PeiServices
     42   )
     43 {
     44   BOOLEAN IsFirstBoot = FALSE;
     45 
     46   BOOLEAN EnableFastBoot = FALSE;
     47   IsFirstBoot = PcdGetBool(PcdBootState);
     48   EnableFastBoot = PcdGetBool (PcdEnableFastBoot);
     49 
     50   DEBUG ((EFI_D_INFO, "IsFirstBoot = %x , EnableFastBoot= %x. \n", IsFirstBoot, EnableFastBoot));
     51 
     52   if ((!IsFirstBoot) && EnableFastBoot) {
     53     return TRUE;
     54   } else {
     55     return FALSE;
     56   }
     57 }
     58 
     59 
     60 /**
     61 
     62 Routine Description:
     63 
     64   This function is used to verify if the FV header is validate.
     65 
     66   @param  FwVolHeader - The FV header that to be verified.
     67 
     68   @retval EFI_SUCCESS   - The Fv header is valid.
     69   @retval EFI_NOT_FOUND - The Fv header is invalid.
     70 
     71 **/
     72 EFI_STATUS
     73 ValidateFvHeader (
     74   EFI_BOOT_MODE      *BootMode
     75   )
     76 {
     77   UINT16  *Ptr;
     78   UINT16  HeaderLength;
     79   UINT16  Checksum;
     80 
     81   EFI_FIRMWARE_VOLUME_HEADER  *FwVolHeader;
     82 
     83   if (BOOT_IN_RECOVERY_MODE == *BootMode) {
     84     DEBUG ((EFI_D_INFO, "Boot mode recovery\n"));
     85     return EFI_SUCCESS;
     86   }
     87   //
     88   // Let's check whether FvMain header is valid, if not enter into recovery mode
     89   //
     90   //
     91   // Verify the header revision, header signature, length
     92   // Length of FvBlock cannot be 2**64-1
     93   // HeaderLength cannot be an odd number
     94   //
     95   FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)PcdGet32(PcdFlashFvMainBase);
     96   if ((FwVolHeader->Revision != EFI_FVH_REVISION)||
     97       (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
     98       (FwVolHeader->FvLength == ((UINT64) -1)) ||
     99       ((FwVolHeader->HeaderLength & 0x01) != 0)
    100       ) {
    101     return EFI_NOT_FOUND;
    102   }
    103   //
    104   // Verify the header checksum
    105   //
    106   HeaderLength  = (UINT16) (FwVolHeader->HeaderLength / 2);
    107   Ptr           = (UINT16 *) FwVolHeader;
    108   Checksum      = 0;
    109   while (HeaderLength > 0) {
    110     Checksum = Checksum +*Ptr;
    111     Ptr++;
    112     HeaderLength--;
    113   }
    114 
    115   if (Checksum != 0) {
    116     return EFI_NOT_FOUND;
    117   }
    118 
    119   return EFI_SUCCESS;
    120 }
    121 
    122 /**
    123   Peform the boot mode determination logic
    124   If the box is closed, then
    125     1. If it's first time to boot, it's boot with full config .
    126     2. If the ChassisIntrution is selected, force to be a boot with full config
    127     3. Otherwise it's boot with no change.
    128 
    129   @param  PeiServices General purpose services available to every PEIM.
    130 
    131   @param  BootMode The detected boot mode.
    132 
    133   @retval EFI_SUCCESS if the boot mode could be set
    134 **/
    135 EFI_STATUS
    136 UpdateBootMode (
    137   IN  EFI_PEI_SERVICES     **PeiServices,
    138   OUT EFI_BOOT_MODE        *BootMode
    139   )
    140 {
    141   EFI_STATUS          Status;
    142   EFI_BOOT_MODE       NewBootMode;
    143   PEI_CAPSULE_PPI     *Capsule;
    144   UINT32              RegValue;
    145 
    146   NewBootMode = *BootMode;
    147 
    148   //
    149   // Read Sticky R/W Bits
    150   //
    151   RegValue = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_CFG_STICKY_RW);
    152   DEBUG ((EFI_D_ERROR, "RegValue = %08x\n", RegValue));
    153 
    154   //
    155   // Check if we need to boot in recovery mode
    156   //
    157   if ((RegValue & B_CFG_STICKY_RW_FORCE_RECOVERY) != 0) {
    158     NewBootMode = BOOT_IN_RECOVERY_MODE;
    159     DEBUG ((EFI_D_ERROR, "RECOVERY from sticky bit\n"));;
    160 
    161     //
    162     // Clear force recovery sticky bit
    163     //
    164     QNCAltPortWrite (
    165       QUARK_SCSS_SOC_UNIT_SB_PORT_ID,
    166       QUARK_SCSS_SOC_UNIT_CFG_STICKY_RW,
    167       RegValue &(~B_CFG_STICKY_RW_FORCE_RECOVERY)
    168       );
    169 
    170   } else if (ValidateFvHeader (BootMode) != EFI_SUCCESS) {
    171     NewBootMode = BOOT_IN_RECOVERY_MODE;
    172     DEBUG ((EFI_D_ERROR, "RECOVERY from corrupt FV\n"));;
    173   } else if (QNCCheckS3AndClearState ()) {
    174     //
    175     // Determine if we're in capsule update mode
    176     //
    177     Status = PeiServicesLocatePpi (
    178                &gPeiCapsulePpiGuid,
    179                0,
    180                NULL,
    181                (VOID **)&Capsule
    182                );
    183     if (Status == EFI_SUCCESS) {
    184       Status = Capsule->CheckCapsuleUpdate (PeiServices);
    185       if (Status == EFI_SUCCESS) {
    186         DEBUG ((EFI_D_INFO, "Boot mode Flash Update\n"));
    187         NewBootMode = BOOT_ON_FLASH_UPDATE;
    188       } else {
    189         DEBUG ((EFI_D_INFO, "Boot mode S3 resume\n"));
    190         NewBootMode = BOOT_ON_S3_RESUME;
    191       }
    192     } else {
    193       DEBUG ((EFI_D_INFO, "Boot mode S3 resume\n"));
    194       NewBootMode = BOOT_ON_S3_RESUME;
    195     }
    196   } else {
    197     //
    198     // Check if this is a power on reset
    199     //
    200     if (QNCCheckPowerOnResetAndClearState ()) {
    201       DEBUG ((EFI_D_INFO, "Power On Reset\n"));
    202     }
    203     if (IsBootWithNoChange (PeiServices)) {
    204       DEBUG ((EFI_D_INFO, "Boot with Minimum cfg\n"));
    205       NewBootMode = BOOT_ASSUMING_NO_CONFIGURATION_CHANGES;
    206     } else {
    207       DEBUG ((EFI_D_INFO, "Boot with Full cfg\n"));
    208       NewBootMode = BOOT_WITH_FULL_CONFIGURATION;
    209     }
    210   }
    211 
    212   if (NewBootMode == BOOT_IN_RECOVERY_MODE) {
    213     DEBUG ((EFI_D_INFO, "Boot mode recovery\n"));
    214     Status = PeiServicesInstallPpi (&mPpiListRecoveryBootMode);
    215     ASSERT_EFI_ERROR (Status);
    216   }
    217 
    218   Status = PeiServicesSetBootMode (NewBootMode);
    219   ASSERT_EFI_ERROR (Status);
    220 
    221   *BootMode = NewBootMode;
    222 
    223   return EFI_SUCCESS;
    224 }
    225