1 /** @file
2   PCH BIOS Write Protect Driver.
3 
4   Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
5   SPDX-License-Identifier: BSD-2-Clause-Patent
6 **/
7 #include "PchInitSmm.h"
8 #include <Register/PchRegs.h>
9 #include <Register/PchRegsLpc.h>
10 #include <Register/SpiRegs.h>
11 #include <Library/SpiAccessPrivateLib.h>
12 #include <Library/PchPciBdfLib.h>
13 
14 //
15 // Global variables
16 //
17 GLOBAL_REMOVE_IF_UNREFERENCED PCH_TCO_SMI_DISPATCH_PROTOCOL     *mPchTcoSmiDispatchProtocol;
18 GLOBAL_REMOVE_IF_UNREFERENCED PCH_ESPI_SMI_DISPATCH_PROTOCOL    *mEspiSmmDispatchProtocol;
19 GLOBAL_REMOVE_IF_UNREFERENCED UINT64                            mLpcRegBase;
20 
21 /**
22   This hardware SMI handler will be run every time the BIOS Write Enable bit is set.
23 
24   @param[in] DispatchHandle       Not used
25 **/
26 VOID
27 EFIAPI
PchSpiBiosWpCallback(IN EFI_HANDLE DispatchHandle)28 PchSpiBiosWpCallback (
29   IN  EFI_HANDLE                              DispatchHandle
30   )
31 {
32   SpiClearBiosWriteProtectDisable ();
33 }
34 
35 /**
36   This hardware SMI handler will be run every time the BIOS Write Enable bit is set.
37 
38   @param[in] DispatchHandle       Not used
39 
40 **/
41 VOID
42 EFIAPI
PchLpcBiosWpCallback(IN EFI_HANDLE DispatchHandle)43 PchLpcBiosWpCallback (
44   IN  EFI_HANDLE                              DispatchHandle
45   )
46 {
47   //
48   // Disable BIOSWE bit to protect BIOS
49   //
50   PciSegmentAnd8 ((UINTN) (mLpcRegBase + R_LPC_CFG_BC), (UINT8) ~B_LPC_CFG_BC_WPD);
51 }
52 
53 /**
54   Entry point for Pch Bios Write Protect driver.
55 
56   @param[in] ImageHandle          Image handle of this driver.
57   @param[in] SystemTable          Global system service table.
58 
59   @retval EFI_SUCCESS             Initialization complete.
60 **/
61 EFI_STATUS
62 EFIAPI
InstallPchBiosWriteProtect(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)63 InstallPchBiosWriteProtect (
64   IN EFI_HANDLE            ImageHandle,
65   IN EFI_SYSTEM_TABLE      *SystemTable
66   )
67 {
68   EFI_STATUS              Status;
69   EFI_HANDLE              Handle;
70 
71   DEBUG ((DEBUG_INFO, "InstallPchBiosWriteProtect()\n"));
72 
73   if (mPchConfigHob->LockDown.BiosLock != TRUE) {
74     return EFI_SUCCESS;
75   }
76 
77   mLpcRegBase = LpcPciCfgBase ();
78 
79   DEBUG ((DEBUG_INFO, "Installing BIOS Write Protect SMI handler\n"));
80   //
81   // Get the PCH TCO SMM dispatch protocol
82   //
83   mPchTcoSmiDispatchProtocol = NULL;
84   Status = gSmst->SmmLocateProtocol (&gPchTcoSmiDispatchProtocolGuid, NULL, (VOID **) &mPchTcoSmiDispatchProtocol);
85   ASSERT_EFI_ERROR (Status);
86   //
87   // Always register an SPI BiosWp callback function to handle TCO BIOSWR SMI
88   // NOTE: No matter the BIOS resides behind SPI or not, it needs to handle the SPI BIOS WP SMI
89   //       to avoid SMI deadloop on SPI WPD write.
90   //
91   Handle = NULL;
92   Status = mPchTcoSmiDispatchProtocol->SpiBiosWpRegister (
93                                          mPchTcoSmiDispatchProtocol,
94                                          PchSpiBiosWpCallback,
95                                          &Handle
96                                          );
97   ASSERT_EFI_ERROR (Status);
98 
99   //
100   // Always register an LPC/eSPI BiosWp callback function to handle TCO BIOSWR SMI
101   // NOTE: No matter the BIOS resides behind LPC/eSPI or not, it needs to handle the BIOS WP SMI
102   //       to avoid SMI deadloop on LPC/eSPI WPD write.
103   //
104   if (IsEspiEnabled ()) {
105     //
106     // Get the PCH ESPI SMM dispatch protocol
107     //
108     mEspiSmmDispatchProtocol = NULL;
109     Status = gSmst->SmmLocateProtocol (&gPchEspiSmiDispatchProtocolGuid, NULL, (VOID **) &mEspiSmmDispatchProtocol);
110     ASSERT_EFI_ERROR (Status);
111 
112     //
113     // Register an ESpiBiosWp callback function to handle BIOSWR SMI
114     //
115     Handle = NULL;
116     Status = mEspiSmmDispatchProtocol->BiosWrProtectRegister (
117                                          mEspiSmmDispatchProtocol,
118                                          PchLpcBiosWpCallback,
119                                          &Handle
120                                          );
121     ASSERT_EFI_ERROR (Status);
122   } else {
123     //
124     // Register an LPC BiosWp callback function to handle TCO BIOSWR SMI
125     //
126     Handle = NULL;
127     Status = mPchTcoSmiDispatchProtocol->LpcBiosWpRegister (
128                                            mPchTcoSmiDispatchProtocol,
129                                            PchLpcBiosWpCallback,
130                                            &Handle
131                                            );
132     ASSERT_EFI_ERROR (Status);
133   }
134 
135   return EFI_SUCCESS;
136 }
137 
138