Home | History | Annotate | Download | only in DxeTrEEPhysicalPresenceLib
      1 /** @file
      2   Execute pending TPM2 requests from OS or BIOS.
      3 
      4   Caution: This module requires additional review when modified.
      5   This driver will have external input - variable.
      6   This external input must be validated carefully to avoid security issue.
      7 
      8   TrEEExecutePendingTpmRequest() will receive untrusted input and do validation.
      9 
     10 Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
     11 This program and the accompanying materials
     12 are licensed and made available under the terms and conditions of the BSD License
     13 which accompanies this distribution.  The full text of the license may be found at
     14 http://opensource.org/licenses/bsd-license.php
     15 
     16 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     17 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     18 
     19 **/
     20 
     21 #include <PiDxe.h>
     22 
     23 #include <Protocol/TrEEProtocol.h>
     24 #include <Protocol/VariableLock.h>
     25 #include <Library/DebugLib.h>
     26 #include <Library/BaseMemoryLib.h>
     27 #include <Library/UefiRuntimeServicesTableLib.h>
     28 #include <Library/UefiDriverEntryPoint.h>
     29 #include <Library/UefiBootServicesTableLib.h>
     30 #include <Library/UefiLib.h>
     31 #include <Library/MemoryAllocationLib.h>
     32 #include <Library/PrintLib.h>
     33 #include <Library/HiiLib.h>
     34 #include <Guid/EventGroup.h>
     35 #include <Guid/TrEEPhysicalPresenceData.h>
     36 #include <Library/Tpm2CommandLib.h>
     37 #include <Library/TrEEPpVendorLib.h>
     38 
     39 #define CONFIRM_BUFFER_SIZE         4096
     40 
     41 EFI_HII_HANDLE mTrEEPpStringPackHandle;
     42 
     43 /**
     44   Get string by string id from HII Interface.
     45 
     46   @param[in] Id          String ID.
     47 
     48   @retval    CHAR16 *    String from ID.
     49   @retval    NULL        If error occurs.
     50 
     51 **/
     52 CHAR16 *
     53 TrEEPhysicalPresenceGetStringById (
     54   IN  EFI_STRING_ID   Id
     55   )
     56 {
     57   return HiiGetString (mTrEEPpStringPackHandle, Id, NULL);
     58 }
     59 
     60 /**
     61   Send ClearControl and Clear command to TPM.
     62 
     63   @param[in]  PlatformAuth      platform auth value. NULL means no platform auth change.
     64 
     65   @retval EFI_SUCCESS           Operation completed successfully.
     66   @retval EFI_TIMEOUT           The register can't run into the expected status in time.
     67   @retval EFI_BUFFER_TOO_SMALL  Response data buffer is too small.
     68   @retval EFI_DEVICE_ERROR      Unexpected device behavior.
     69 
     70 **/
     71 EFI_STATUS
     72 EFIAPI
     73 TpmCommandClear (
     74   IN TPM2B_AUTH                *PlatformAuth  OPTIONAL
     75   )
     76 {
     77   EFI_STATUS                Status;
     78   TPMS_AUTH_COMMAND         *AuthSession;
     79   TPMS_AUTH_COMMAND         LocalAuthSession;
     80 
     81   if (PlatformAuth == NULL) {
     82     AuthSession = NULL;
     83   } else {
     84     AuthSession = &LocalAuthSession;
     85     ZeroMem (&LocalAuthSession, sizeof(LocalAuthSession));
     86     LocalAuthSession.sessionHandle = TPM_RS_PW;
     87     LocalAuthSession.hmac.size = PlatformAuth->size;
     88     CopyMem (LocalAuthSession.hmac.buffer, PlatformAuth->buffer, PlatformAuth->size);
     89   }
     90 
     91   DEBUG ((EFI_D_INFO, "Tpm2ClearControl ... \n"));
     92   Status = Tpm2ClearControl (TPM_RH_PLATFORM, AuthSession, NO);
     93   DEBUG ((EFI_D_INFO, "Tpm2ClearControl - %r\n", Status));
     94   if (EFI_ERROR (Status)) {
     95     goto Done;
     96   }
     97   DEBUG ((EFI_D_INFO, "Tpm2Clear ... \n"));
     98   Status = Tpm2Clear (TPM_RH_PLATFORM, AuthSession);
     99   DEBUG ((EFI_D_INFO, "Tpm2Clear - %r\n", Status));
    100 
    101 Done:
    102   ZeroMem (&LocalAuthSession.hmac, sizeof(LocalAuthSession.hmac));
    103   return Status;
    104 }
    105 
    106 /**
    107   Execute physical presence operation requested by the OS.
    108 
    109   @param[in]      PlatformAuth        platform auth value. NULL means no platform auth change.
    110   @param[in]      CommandCode         Physical presence operation value.
    111   @param[in, out] PpiFlags            The physical presence interface flags.
    112 
    113   @retval TREE_PP_OPERATION_RESPONSE_BIOS_FAILURE  Unknown physical presence operation.
    114   @retval TREE_PP_OPERATION_RESPONSE_BIOS_FAILURE  Error occurred during sending command to TPM or
    115                                                    receiving response from TPM.
    116   @retval Others                                   Return code from the TPM device after command execution.
    117 **/
    118 UINT32
    119 TrEEExecutePhysicalPresence (
    120   IN      TPM2B_AUTH                       *PlatformAuth,  OPTIONAL
    121   IN      UINT32                           CommandCode,
    122   IN OUT  EFI_TREE_PHYSICAL_PRESENCE_FLAGS *PpiFlags
    123   )
    124 {
    125   EFI_STATUS  Status;
    126 
    127   switch (CommandCode) {
    128     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR:
    129     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2:
    130     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3:
    131     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4:
    132       Status = TpmCommandClear (PlatformAuth);
    133       if (EFI_ERROR (Status)) {
    134         return TREE_PP_OPERATION_RESPONSE_BIOS_FAILURE;
    135       } else {
    136         return TREE_PP_OPERATION_RESPONSE_SUCCESS;
    137       }
    138 
    139     case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE:
    140       PpiFlags->PPFlags &= ~TREE_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR;
    141       return TREE_PP_OPERATION_RESPONSE_SUCCESS;
    142 
    143     case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE:
    144       PpiFlags->PPFlags |= TREE_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR;
    145       return TREE_PP_OPERATION_RESPONSE_SUCCESS;
    146 
    147     default:
    148       if (CommandCode <= TREE_PHYSICAL_PRESENCE_NO_ACTION_MAX) {
    149         return TREE_PP_OPERATION_RESPONSE_SUCCESS;
    150       } else {
    151         return TREE_PP_OPERATION_RESPONSE_BIOS_FAILURE;
    152       }
    153   }
    154 }
    155 
    156 
    157 /**
    158   Read the specified key for user confirmation.
    159 
    160   @param[in]  CautionKey  If true,  F12 is used as confirm key;
    161                           If false, F10 is used as confirm key.
    162 
    163   @retval     TRUE        User confirmed the changes by input.
    164   @retval     FALSE       User discarded the changes.
    165 **/
    166 BOOLEAN
    167 TrEEReadUserKey (
    168   IN     BOOLEAN                    CautionKey
    169   )
    170 {
    171   EFI_STATUS                        Status;
    172   EFI_INPUT_KEY                     Key;
    173   UINT16                            InputKey;
    174 
    175   InputKey = 0;
    176   do {
    177     Status = gBS->CheckEvent (gST->ConIn->WaitForKey);
    178     if (!EFI_ERROR (Status)) {
    179       Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
    180       if (Key.ScanCode == SCAN_ESC) {
    181         InputKey = Key.ScanCode;
    182       }
    183       if ((Key.ScanCode == SCAN_F10) && !CautionKey) {
    184         InputKey = Key.ScanCode;
    185       }
    186       if ((Key.ScanCode == SCAN_F12) && CautionKey) {
    187         InputKey = Key.ScanCode;
    188       }
    189     }
    190   } while (InputKey == 0);
    191 
    192   if (InputKey != SCAN_ESC) {
    193     return TRUE;
    194   }
    195 
    196   return FALSE;
    197 }
    198 
    199 /**
    200   The constructor function register UNI strings into imageHandle.
    201 
    202   It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.
    203 
    204   @param  ImageHandle   The firmware allocated handle for the EFI image.
    205   @param  SystemTable   A pointer to the EFI System Table.
    206 
    207   @retval EFI_SUCCESS   The constructor successfully added string package.
    208   @retval Other value   The constructor can't add string package.
    209 **/
    210 EFI_STATUS
    211 EFIAPI
    212 TrEEPhysicalPresenceLibConstructor (
    213   IN EFI_HANDLE        ImageHandle,
    214   IN EFI_SYSTEM_TABLE  *SystemTable
    215   )
    216 {
    217   mTrEEPpStringPackHandle = HiiAddPackages (&gEfiTrEEPhysicalPresenceGuid, ImageHandle, DxeTrEEPhysicalPresenceLibStrings, NULL);
    218   ASSERT (mTrEEPpStringPackHandle != NULL);
    219 
    220   return EFI_SUCCESS;
    221 }
    222 
    223 /**
    224   Display the confirm text and get user confirmation.
    225 
    226   @param[in] TpmPpCommand  The requested TPM physical presence command.
    227 
    228   @retval    TRUE          The user has confirmed the changes.
    229   @retval    FALSE         The user doesn't confirm the changes.
    230 **/
    231 BOOLEAN
    232 TrEEUserConfirm (
    233   IN      UINT32                    TpmPpCommand
    234   )
    235 {
    236   CHAR16                            *ConfirmText;
    237   CHAR16                            *TmpStr1;
    238   CHAR16                            *TmpStr2;
    239   UINTN                             BufSize;
    240   BOOLEAN                           CautionKey;
    241   UINT16                            Index;
    242   CHAR16                            DstStr[81];
    243 
    244   TmpStr2     = NULL;
    245   CautionKey  = FALSE;
    246   BufSize     = CONFIRM_BUFFER_SIZE;
    247   ConfirmText = AllocateZeroPool (BufSize);
    248   ASSERT (ConfirmText != NULL);
    249 
    250   switch (TpmPpCommand) {
    251 
    252     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR:
    253     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2:
    254     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3:
    255     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4:
    256       CautionKey = TRUE;
    257       TmpStr2 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_CLEAR));
    258 
    259       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
    260       UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
    261       FreePool (TmpStr1);
    262 
    263       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CLEAR));
    264       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
    265       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), L" \n\n", (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
    266       FreePool (TmpStr1);
    267 
    268       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY));
    269       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
    270       FreePool (TmpStr1);
    271       break;
    272 
    273     case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE:
    274       CautionKey = TRUE;
    275       TmpStr2 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_CLEAR));
    276 
    277       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_PPI_HEAD_STR));
    278       UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
    279       FreePool (TmpStr1);
    280 
    281       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_NOTE_CLEAR));
    282       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
    283       FreePool (TmpStr1);
    284 
    285       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CLEAR));
    286       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
    287       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), L" \n\n", (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
    288       FreePool (TmpStr1);
    289 
    290       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY));
    291       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
    292       FreePool (TmpStr1);
    293 
    294       TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_NO_PPI_INFO));
    295       StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
    296       FreePool (TmpStr1);
    297       break;
    298 
    299     default:
    300       ;
    301   }
    302 
    303   if (TmpStr2 == NULL) {
    304     FreePool (ConfirmText);
    305     return FALSE;
    306   }
    307 
    308   TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_REJECT_KEY));
    309   BufSize -= StrSize (ConfirmText);
    310   UnicodeSPrint (ConfirmText + StrLen (ConfirmText), BufSize, TmpStr1, TmpStr2);
    311 
    312   DstStr[80] = L'\0';
    313   for (Index = 0; Index < StrLen (ConfirmText); Index += 80) {
    314     StrnCpyS(DstStr, sizeof (DstStr) / sizeof (CHAR16), ConfirmText + Index, sizeof (DstStr) / sizeof (CHAR16) - 1);
    315     Print (DstStr);
    316   }
    317 
    318   FreePool (TmpStr1);
    319   FreePool (TmpStr2);
    320   FreePool (ConfirmText);
    321 
    322   if (TrEEReadUserKey (CautionKey)) {
    323     return TRUE;
    324   }
    325 
    326   return FALSE;
    327 }
    328 
    329 /**
    330   Check if there is a valid physical presence command request. Also updates parameter value
    331   to whether the requested physical presence command already confirmed by user
    332 
    333    @param[in]  TcgPpData                 EFI TrEE Physical Presence request data.
    334    @param[in]  Flags                     The physical presence interface flags.
    335    @param[out] RequestConfirmed            If the physical presence operation command required user confirm from UI.
    336                                              True, it indicates the command doesn't require user confirm, or already confirmed
    337                                                    in last boot cycle by user.
    338                                              False, it indicates the command need user confirm from UI.
    339 
    340    @retval  TRUE        Physical Presence operation command is valid.
    341    @retval  FALSE       Physical Presence operation command is invalid.
    342 
    343 **/
    344 BOOLEAN
    345 TrEEHaveValidTpmRequest  (
    346   IN      EFI_TREE_PHYSICAL_PRESENCE       *TcgPpData,
    347   IN      EFI_TREE_PHYSICAL_PRESENCE_FLAGS Flags,
    348   OUT     BOOLEAN                          *RequestConfirmed
    349   )
    350 {
    351   BOOLEAN  IsRequestValid;
    352 
    353   *RequestConfirmed = FALSE;
    354 
    355   switch (TcgPpData->PPRequest) {
    356     case TREE_PHYSICAL_PRESENCE_NO_ACTION:
    357       *RequestConfirmed = TRUE;
    358       return TRUE;
    359     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR:
    360     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2:
    361     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3:
    362     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4:
    363       if ((Flags.PPFlags & TREE_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR) != 0) {
    364         *RequestConfirmed = TRUE;
    365       }
    366       break;
    367 
    368     case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE:
    369       *RequestConfirmed = TRUE;
    370       break;
    371 
    372     case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE:
    373       break;
    374 
    375     default:
    376       if (TcgPpData->PPRequest >= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
    377         IsRequestValid = TrEEPpVendorLibHasValidRequest (TcgPpData->PPRequest, Flags.PPFlags, RequestConfirmed);
    378         if (!IsRequestValid) {
    379           return FALSE;
    380         } else {
    381           break;
    382         }
    383       } else {
    384         //
    385         // Wrong Physical Presence command
    386         //
    387         return FALSE;
    388       }
    389   }
    390 
    391   if ((Flags.PPFlags & TREE_VENDOR_LIB_FLAG_RESET_TRACK) != 0) {
    392     //
    393     // It had been confirmed in last boot, it doesn't need confirm again.
    394     //
    395     *RequestConfirmed = TRUE;
    396   }
    397 
    398   //
    399   // Physical Presence command is correct
    400   //
    401   return TRUE;
    402 }
    403 
    404 
    405 /**
    406   Check and execute the requested physical presence command.
    407 
    408   Caution: This function may receive untrusted input.
    409   TcgPpData variable is external input, so this function will validate
    410   its data structure to be valid value.
    411 
    412   @param[in] PlatformAuth         platform auth value. NULL means no platform auth change.
    413   @param[in] TcgPpData            Point to the physical presence NV variable.
    414   @param[in] Flags                The physical presence interface flags.
    415 **/
    416 VOID
    417 TrEEExecutePendingTpmRequest (
    418   IN      TPM2B_AUTH                       *PlatformAuth,  OPTIONAL
    419   IN      EFI_TREE_PHYSICAL_PRESENCE       *TcgPpData,
    420   IN      EFI_TREE_PHYSICAL_PRESENCE_FLAGS Flags
    421   )
    422 {
    423   EFI_STATUS                        Status;
    424   UINTN                             DataSize;
    425   BOOLEAN                           RequestConfirmed;
    426   EFI_TREE_PHYSICAL_PRESENCE_FLAGS  NewFlags;
    427   BOOLEAN                           ResetRequired;
    428   UINT32                            NewPPFlags;
    429 
    430   if (TcgPpData->PPRequest == TREE_PHYSICAL_PRESENCE_NO_ACTION) {
    431     //
    432     // No operation request
    433     //
    434     return;
    435   }
    436 
    437   if (!TrEEHaveValidTpmRequest(TcgPpData, Flags, &RequestConfirmed)) {
    438     //
    439     // Invalid operation request.
    440     //
    441     if (TcgPpData->PPRequest <= TREE_PHYSICAL_PRESENCE_NO_ACTION_MAX) {
    442       TcgPpData->PPResponse = TREE_PP_OPERATION_RESPONSE_SUCCESS;
    443     } else {
    444       TcgPpData->PPResponse = TREE_PP_OPERATION_RESPONSE_BIOS_FAILURE;
    445     }
    446     TcgPpData->LastPPRequest = TcgPpData->PPRequest;
    447     TcgPpData->PPRequest = TREE_PHYSICAL_PRESENCE_NO_ACTION;
    448     DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
    449     Status = gRT->SetVariable (
    450                     TREE_PHYSICAL_PRESENCE_VARIABLE,
    451                     &gEfiTrEEPhysicalPresenceGuid,
    452                     EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
    453                     DataSize,
    454                     TcgPpData
    455                     );
    456     return;
    457   }
    458 
    459   ResetRequired = FALSE;
    460   if (TcgPpData->PPRequest >= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
    461     NewFlags = Flags;
    462     NewPPFlags = NewFlags.PPFlags;
    463     TcgPpData->PPResponse = TrEEPpVendorLibExecutePendingRequest (PlatformAuth, TcgPpData->PPRequest, &NewPPFlags, &ResetRequired);
    464     NewFlags.PPFlags = (UINT8)NewPPFlags;
    465   } else {
    466     if (!RequestConfirmed) {
    467       //
    468       // Print confirm text and wait for approval.
    469       //
    470       RequestConfirmed = TrEEUserConfirm (TcgPpData->PPRequest
    471                                           );
    472     }
    473 
    474     //
    475     // Execute requested physical presence command
    476     //
    477     TcgPpData->PPResponse = TREE_PP_OPERATION_RESPONSE_USER_ABORT;
    478     NewFlags = Flags;
    479     if (RequestConfirmed) {
    480       TcgPpData->PPResponse = TrEEExecutePhysicalPresence (PlatformAuth, TcgPpData->PPRequest,
    481                                                            &NewFlags);
    482     }
    483   }
    484 
    485   //
    486   // Save the flags if it is updated.
    487   //
    488   if (CompareMem (&Flags, &NewFlags, sizeof(EFI_TREE_PHYSICAL_PRESENCE_FLAGS)) != 0) {
    489     Status   = gRT->SetVariable (
    490                       TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
    491                       &gEfiTrEEPhysicalPresenceGuid,
    492                       EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
    493                       sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS),
    494                       &NewFlags
    495                       );
    496   }
    497 
    498   //
    499   // Clear request
    500   //
    501   if ((NewFlags.PPFlags & TREE_VENDOR_LIB_FLAG_RESET_TRACK) == 0) {
    502     TcgPpData->LastPPRequest = TcgPpData->PPRequest;
    503     TcgPpData->PPRequest = TREE_PHYSICAL_PRESENCE_NO_ACTION;
    504   }
    505 
    506   //
    507   // Save changes
    508   //
    509   DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
    510   Status = gRT->SetVariable (
    511                   TREE_PHYSICAL_PRESENCE_VARIABLE,
    512                   &gEfiTrEEPhysicalPresenceGuid,
    513                   EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
    514                   DataSize,
    515                   TcgPpData
    516                   );
    517   if (EFI_ERROR (Status)) {
    518     return;
    519   }
    520 
    521   if (TcgPpData->PPResponse == TREE_PP_OPERATION_RESPONSE_USER_ABORT) {
    522     return;
    523   }
    524 
    525   //
    526   // Reset system to make new TPM settings in effect
    527   //
    528   switch (TcgPpData->LastPPRequest) {
    529     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR:
    530     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2:
    531     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3:
    532     case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4:
    533       break;
    534     default:
    535       if (TcgPpData->LastPPRequest >= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
    536         if (ResetRequired) {
    537           break;
    538         } else {
    539           return ;
    540         }
    541       }
    542       if (TcgPpData->PPRequest != TREE_PHYSICAL_PRESENCE_NO_ACTION) {
    543         break;
    544       }
    545       return;
    546   }
    547 
    548   Print (L"Rebooting system to make TPM2 settings in effect\n");
    549   gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
    550   ASSERT (FALSE);
    551 }
    552 
    553 /**
    554   Check and execute the pending TPM request.
    555 
    556   The TPM request may come from OS or BIOS. This API will display request information and wait
    557   for user confirmation if TPM request exists. The TPM request will be sent to TPM device after
    558   the TPM request is confirmed, and one or more reset may be required to make TPM request to
    559   take effect.
    560 
    561   This API should be invoked after console in and console out are all ready as they are required
    562   to display request information and get user input to confirm the request.
    563 
    564   @param[in]  PlatformAuth                   platform auth value. NULL means no platform auth change.
    565 **/
    566 VOID
    567 EFIAPI
    568 TrEEPhysicalPresenceLibProcessRequest (
    569   IN      TPM2B_AUTH                     *PlatformAuth  OPTIONAL
    570   )
    571 {
    572   EFI_STATUS                        Status;
    573   UINTN                             DataSize;
    574   EFI_TREE_PHYSICAL_PRESENCE        TcgPpData;
    575   EFI_TREE_PROTOCOL                 *TreeProtocol;
    576   EDKII_VARIABLE_LOCK_PROTOCOL      *VariableLockProtocol;
    577   EFI_TREE_PHYSICAL_PRESENCE_FLAGS  PpiFlags;
    578 
    579   Status = gBS->LocateProtocol (&gEfiTrEEProtocolGuid, NULL, (VOID **) &TreeProtocol);
    580   if (EFI_ERROR (Status)) {
    581     return ;
    582   }
    583 
    584   //
    585   // Initialize physical presence flags.
    586   //
    587   DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS);
    588   Status = gRT->GetVariable (
    589                   TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
    590                   &gEfiTrEEPhysicalPresenceGuid,
    591                   NULL,
    592                   &DataSize,
    593                   &PpiFlags
    594                   );
    595   if (EFI_ERROR (Status)) {
    596     PpiFlags.PPFlags = 0;
    597     Status   = gRT->SetVariable (
    598                       TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
    599                       &gEfiTrEEPhysicalPresenceGuid,
    600                       EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
    601                       sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS),
    602                       &PpiFlags
    603                       );
    604     if (EFI_ERROR (Status)) {
    605       DEBUG ((EFI_D_ERROR, "[TPM2] Set physical presence flag failed, Status = %r\n", Status));
    606       return ;
    607     }
    608   }
    609   DEBUG ((EFI_D_INFO, "[TPM2] PpiFlags = %x\n", PpiFlags.PPFlags));
    610 
    611   //
    612   // This flags variable controls whether physical presence is required for TPM command.
    613   // It should be protected from malicious software. We set it as read-only variable here.
    614   //
    615   Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLockProtocol);
    616   if (!EFI_ERROR (Status)) {
    617     Status = VariableLockProtocol->RequestToLock (
    618                                      VariableLockProtocol,
    619                                      TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
    620                                      &gEfiTrEEPhysicalPresenceGuid
    621                                      );
    622     if (EFI_ERROR (Status)) {
    623       DEBUG ((EFI_D_ERROR, "[TPM2] Error when lock variable %s, Status = %r\n", TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE, Status));
    624       ASSERT_EFI_ERROR (Status);
    625     }
    626   }
    627 
    628   //
    629   // Initialize physical presence variable.
    630   //
    631   DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
    632   Status = gRT->GetVariable (
    633                   TREE_PHYSICAL_PRESENCE_VARIABLE,
    634                   &gEfiTrEEPhysicalPresenceGuid,
    635                   NULL,
    636                   &DataSize,
    637                   &TcgPpData
    638                   );
    639   if (EFI_ERROR (Status)) {
    640     ZeroMem ((VOID*)&TcgPpData, sizeof (TcgPpData));
    641     DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
    642     Status   = gRT->SetVariable (
    643                       TREE_PHYSICAL_PRESENCE_VARIABLE,
    644                       &gEfiTrEEPhysicalPresenceGuid,
    645                       EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
    646                       DataSize,
    647                       &TcgPpData
    648                       );
    649     if (EFI_ERROR (Status)) {
    650       DEBUG ((EFI_D_ERROR, "[TPM2] Set physical presence variable failed, Status = %r\n", Status));
    651       return ;
    652     }
    653   }
    654 
    655   DEBUG ((EFI_D_INFO, "[TPM2] Flags=%x, PPRequest=%x (LastPPRequest=%x)\n", PpiFlags.PPFlags, TcgPpData.PPRequest, TcgPpData.LastPPRequest));
    656 
    657   //
    658   // Execute pending TPM request.
    659   //
    660   TrEEExecutePendingTpmRequest (PlatformAuth, &TcgPpData, PpiFlags);
    661   DEBUG ((EFI_D_INFO, "[TPM2] PPResponse = %x (LastPPRequest=%x, Flags=%x)\n", TcgPpData.PPResponse, TcgPpData.LastPPRequest, PpiFlags.PPFlags));
    662 
    663 }
    664 
    665 /**
    666   Check if the pending TPM request needs user input to confirm.
    667 
    668   The TPM request may come from OS. This API will check if TPM request exists and need user
    669   input to confirmation.
    670 
    671   @retval    TRUE        TPM needs input to confirm user physical presence.
    672   @retval    FALSE       TPM doesn't need input to confirm user physical presence.
    673 
    674 **/
    675 BOOLEAN
    676 EFIAPI
    677 TrEEPhysicalPresenceLibNeedUserConfirm(
    678   VOID
    679   )
    680 {
    681   EFI_STATUS                        Status;
    682   EFI_TREE_PHYSICAL_PRESENCE        TcgPpData;
    683   UINTN                             DataSize;
    684   BOOLEAN                           RequestConfirmed;
    685   EFI_TREE_PROTOCOL                 *TreeProtocol;
    686   EFI_TREE_PHYSICAL_PRESENCE_FLAGS  PpiFlags;
    687 
    688   Status = gBS->LocateProtocol (&gEfiTrEEProtocolGuid, NULL, (VOID **) &TreeProtocol);
    689   if (EFI_ERROR (Status)) {
    690     return FALSE;
    691   }
    692 
    693   //
    694   // Check Tpm requests
    695   //
    696   DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
    697   Status = gRT->GetVariable (
    698                   TREE_PHYSICAL_PRESENCE_VARIABLE,
    699                   &gEfiTrEEPhysicalPresenceGuid,
    700                   NULL,
    701                   &DataSize,
    702                   &TcgPpData
    703                   );
    704   if (EFI_ERROR (Status)) {
    705     return FALSE;
    706   }
    707 
    708   DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS);
    709   Status = gRT->GetVariable (
    710                   TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
    711                   &gEfiTrEEPhysicalPresenceGuid,
    712                   NULL,
    713                   &DataSize,
    714                   &PpiFlags
    715                   );
    716   if (EFI_ERROR (Status)) {
    717     return FALSE;
    718   }
    719 
    720   if (TcgPpData.PPRequest == TREE_PHYSICAL_PRESENCE_NO_ACTION) {
    721     //
    722     // No operation request
    723     //
    724     return FALSE;
    725   }
    726 
    727   if (!TrEEHaveValidTpmRequest(&TcgPpData, PpiFlags, &RequestConfirmed)) {
    728     //
    729     // Invalid operation request.
    730     //
    731     return FALSE;
    732   }
    733 
    734   if (!RequestConfirmed) {
    735     //
    736     // Need UI to confirm
    737     //
    738     return TRUE;
    739   }
    740 
    741   return FALSE;
    742 }
    743 
    744