1 /** @file
2   This function handle the register/unregister of PCH specific SMI events.
3 
4   Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
5   SPDX-License-Identifier: BSD-2-Clause-Patent
6 **/
7 #include "PchSmmHelpers.h"
8 #include <Library/SmiHandlerProfileLib.h>
9 #include <Register/PchRegs.h>
10 #include <Register/PchPcrRegs.h>
11 #include <Register/PmcRegs.h>
12 #include <Register/PchRegsLpc.h>
13 #include <Register/SpiRegs.h>
14 #include <Register/PchPcieRpRegs.h>
15 #include <Register/PchRegsPsth.h>
16 #include <Library/PchPciBdfLib.h>
17 #include <Library/S3BootScriptLib.h>
18 #include <PchBdfAssignment.h>
19 #include "PchSmiHelper.h"
20 
21 /**
22   The internal function used to create and insert a database record
23   for SMI record of Pch Smi types.
24 
25   @param[in]  SrcDesc                   The pointer to the SMI source description
26   @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
27   @param[in]  PchSmiType                Specific SMI type of PCH SMI
28   @param[out] DispatchHandle            Handle of dispatch function to register.
29 
30   @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
31   @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
32   @retval EFI_SUCCESS                   The database record is created successfully.
33 **/
34 EFI_STATUS
PchSmiRecordInsert(IN CONST PCH_SMM_SOURCE_DESC * SrcDesc,IN PCH_SMI_CALLBACK_FUNCTIONS DispatchFunction,IN PCH_SMI_TYPES PchSmiType,OUT EFI_HANDLE * DispatchHandle)35 PchSmiRecordInsert (
36   IN  CONST PCH_SMM_SOURCE_DESC         *SrcDesc,
37   IN  PCH_SMI_CALLBACK_FUNCTIONS        DispatchFunction,
38   IN  PCH_SMI_TYPES                     PchSmiType,
39   OUT EFI_HANDLE                        *DispatchHandle
40   )
41 {
42   EFI_STATUS                            Status;
43   DATABASE_RECORD                       Record;
44 
45   if (SrcDesc == NULL) {
46     return EFI_INVALID_PARAMETER;
47   }
48 
49   ZeroMem (&Record, sizeof (DATABASE_RECORD));
50   //
51   // Gather information about the registration request
52   //
53   Record.Signature                      = DATABASE_RECORD_SIGNATURE;
54   Record.PchSmiCallback                 = DispatchFunction;
55   Record.ProtocolType                   = PchSmiDispatchType;
56   Record.PchSmiType                     = PchSmiType;
57 
58   CopyMem (&Record.SrcDesc, SrcDesc, sizeof (PCH_SMM_SOURCE_DESC));
59   Status = SmmCoreInsertRecord (
60              &Record,
61              DispatchHandle
62              );
63   ASSERT_EFI_ERROR (Status);
64 
65   return EFI_SUCCESS;
66 }
67 
68 
69 //
70 // TCO_STS bit that needs to be cleared
71 //
72 GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mDescSrcTcoSts = {
73   PCH_SMM_NO_FLAGS,
74   {
75     NULL_BIT_DESC_INITIALIZER,
76     NULL_BIT_DESC_INITIALIZER
77   },
78   {
79     {
80       {
81         ACPI_ADDR_TYPE,
82         {R_ACPI_IO_SMI_STS}
83       },
84       S_ACPI_IO_SMI_STS,
85       N_ACPI_IO_SMI_STS_TCO
86     }
87   },
88   NULL_BIT_DESC_INITIALIZER
89 };
90 
91 /**
92   Clear the TCO SMI status bit and block after the SMI handling is done
93 
94   @param[in] SrcDesc                    Pointer to the PCH SMI source description table
95 
96 **/
97 VOID
98 EFIAPI
PchTcoSmiClearSourceAndBlock(CONST PCH_SMM_SOURCE_DESC * SrcDesc)99 PchTcoSmiClearSourceAndBlock (
100   CONST PCH_SMM_SOURCE_DESC             *SrcDesc
101   )
102 {
103   PchSmmClearSourceAndBlock (SrcDesc);
104   //
105   // Any TCO-based status bits require special handling.
106   // SMI_STS.TCO_STS must be cleared in addition to the status bit in the TCO registers
107   //
108   PchSmmClearSource (&mDescSrcTcoSts);
109 }
110 
111 /**
112   Clear the TCO SMI status bit after the SMI handling is done
113 
114   @param[in] SrcDesc                    Pointer to the PCH SMI source description table
115 
116 **/
117 VOID
118 EFIAPI
PchTcoSmiClearSource(CONST PCH_SMM_SOURCE_DESC * SrcDesc)119 PchTcoSmiClearSource (
120   CONST PCH_SMM_SOURCE_DESC             *SrcDesc
121   )
122 {
123   PchSmmClearSource (SrcDesc);
124   //
125   // Any TCO-based status bits require special handling.
126   // SMI_STS.TCO_STS must be cleared in addition to the status bit in the TCO registers
127   //
128   PchSmmClearSource (&mDescSrcTcoSts);
129 }
130 
131 /**
132   Initialize Source descriptor structure
133 
134    @param[in] SrcDesc                    Pointer to the PCH SMI source description table
135 
136 **/
137 VOID
138 EFIAPI
NullInitSourceDesc(PCH_SMM_SOURCE_DESC * SrcDesc)139 NullInitSourceDesc (
140    PCH_SMM_SOURCE_DESC                   *SrcDesc
141    )
142 {
143   ZeroMem (SrcDesc, sizeof (PCH_SMM_SOURCE_DESC));
144   SrcDesc->En[0].Reg.Type = PCH_SMM_ADDR_TYPE_NULL;
145   SrcDesc->En[1].Reg.Type = PCH_SMM_ADDR_TYPE_NULL;
146   SrcDesc->Sts[0].Reg.Type = PCH_SMM_ADDR_TYPE_NULL;
147   SrcDesc->PmcSmiSts.Reg.Type = PCH_SMM_ADDR_TYPE_NULL;
148 }
149 
150 //
151 // Mch srcdesc
152 //
153 GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescMch = {
154   PCH_SMM_NO_FLAGS,
155   {
156     {
157       {
158         ACPI_ADDR_TYPE,
159         {R_ACPI_IO_SMI_EN}
160       },
161       S_ACPI_IO_SMI_EN,
162       N_ACPI_IO_SMI_EN_TCO
163     },
164     NULL_BIT_DESC_INITIALIZER
165   },
166   {
167     {
168       {
169         TCO_ADDR_TYPE,
170         {R_TCO_IO_TCO1_STS}
171       },
172       S_TCO_IO_TCO1_STS,
173       N_TCO_IO_TCO1_STS_DMISMI
174     }
175   },
176   {
177     {
178       ACPI_ADDR_TYPE,
179       {R_ACPI_IO_SMI_STS}
180     },
181     S_ACPI_IO_SMI_STS,
182     N_ACPI_IO_SMI_STS_TCO
183   }
184 };
185 
186 /**
187   The register function used to register SMI handler of MCH event.
188 
189   @param[in]  This                      The pointer to the protocol itself
190   @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
191   @param[out] DispatchHandle            Handle of dispatch function to register.
192 
193   @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
194   @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
195   @retval EFI_SUCCESS                   The database record is created successfully.
196   @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
197 **/
198 EFI_STATUS
199 EFIAPI
PchTcoSmiMchRegister(IN PCH_TCO_SMI_DISPATCH_PROTOCOL * This,IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)200 PchTcoSmiMchRegister (
201   IN  PCH_TCO_SMI_DISPATCH_PROTOCOL     *This,
202   IN  PCH_TCO_SMI_DISPATCH_CALLBACK     DispatchFunction,
203   OUT EFI_HANDLE                        *DispatchHandle
204   )
205 {
206   EFI_STATUS                            Status;
207   DATABASE_RECORD                       *Record;
208 
209   //
210   // Return access denied if the SmmReadyToLock event has been triggered
211   //
212   if (mReadyToLock == TRUE) {
213     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
214     return EFI_ACCESS_DENIED;
215   }
216 
217   Status = PchSmiRecordInsert (
218              &mSrcDescMch,
219              (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
220              PchTcoSmiMchType,
221              DispatchHandle
222              );
223   if (!EFI_ERROR (Status)) {
224     Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
225     Record->ClearSource = PchTcoSmiClearSource;
226     PchSmmClearSource (&Record->SrcDesc);
227     PchSmmEnableSource (&Record->SrcDesc);
228     SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
229   }
230   return Status;
231 }
232 
233 //
234 // TcoTimeout srcdesc
235 //
236 GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescTcoTimeout = {
237   PCH_SMM_NO_FLAGS,
238   {
239     {
240       {
241         ACPI_ADDR_TYPE,
242         {R_ACPI_IO_SMI_EN}
243       },
244       S_ACPI_IO_SMI_EN,
245       N_ACPI_IO_SMI_EN_TCO
246     },
247     NULL_BIT_DESC_INITIALIZER
248   },
249   {
250     {
251       {
252         TCO_ADDR_TYPE,
253         {R_TCO_IO_TCO1_STS}
254       },
255       S_TCO_IO_TCO1_STS,
256       N_TCO_IO_TCO1_STS_TIMEOUT
257     }
258   },
259   {
260     {
261       ACPI_ADDR_TYPE,
262       {R_ACPI_IO_SMI_STS}
263     },
264     S_ACPI_IO_SMI_STS,
265     N_ACPI_IO_SMI_STS_TCO
266   }
267 };
268 
269 /**
270   The register function used to register SMI handler of TcoTimeout event.
271 
272   @param[in]  This                      The pointer to the protocol itself
273   @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
274   @param[out] DispatchHandle            Handle of dispatch function to register.
275 
276   @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
277   @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
278   @retval EFI_SUCCESS                   The database record is created successfully.
279   @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
280 **/
281 EFI_STATUS
282 EFIAPI
PchTcoSmiTcoTimeoutRegister(IN PCH_TCO_SMI_DISPATCH_PROTOCOL * This,IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)283 PchTcoSmiTcoTimeoutRegister (
284   IN  PCH_TCO_SMI_DISPATCH_PROTOCOL     *This,
285   IN  PCH_TCO_SMI_DISPATCH_CALLBACK     DispatchFunction,
286   OUT EFI_HANDLE                        *DispatchHandle
287   )
288 {
289   EFI_STATUS                            Status;
290   DATABASE_RECORD                       *Record;
291 
292   //
293   // Return access denied if the SmmReadyToLock event has been triggered
294   //
295   if (mReadyToLock == TRUE) {
296     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
297     return EFI_ACCESS_DENIED;
298   }
299 
300   Status = PchSmiRecordInsert (
301              &mSrcDescTcoTimeout,
302              (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
303              PchTcoSmiTcoTimeoutType,
304              DispatchHandle
305              );
306   if (!EFI_ERROR (Status)) {
307     Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
308     Record->ClearSource = PchTcoSmiClearSource;
309     PchSmmClearSource (&Record->SrcDesc);
310     PchSmmEnableSource (&Record->SrcDesc);
311     SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
312   }
313   return Status;
314 }
315 
316 //
317 // OsTco srcdesc
318 //
319 GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescOsTco = {
320   PCH_SMM_NO_FLAGS,
321   {
322     {
323       {
324         ACPI_ADDR_TYPE,
325         {R_ACPI_IO_SMI_EN}
326       },
327       S_ACPI_IO_SMI_EN,
328       N_ACPI_IO_SMI_EN_TCO
329     },
330     NULL_BIT_DESC_INITIALIZER
331   },
332   {
333     {
334       {
335         TCO_ADDR_TYPE,
336         {R_TCO_IO_TCO1_STS}
337       },
338       S_TCO_IO_TCO1_STS,
339       N_TCO_IO_TCO1_STS_SW_TCO_SMI
340     }
341   },
342   {
343     {
344       ACPI_ADDR_TYPE,
345       {R_ACPI_IO_SMI_STS}
346     },
347     S_ACPI_IO_SMI_STS,
348     N_ACPI_IO_SMI_STS_TCO
349   }
350 };
351 
352 /**
353   The register function used to register SMI handler of OS TCO event.
354 
355   @param[in]  This                      The pointer to the protocol itself
356   @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
357   @param[out] DispatchHandle            Handle of dispatch function to register.
358 
359   @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
360   @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
361   @retval EFI_SUCCESS                   The database record is created successfully.
362   @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
363 **/
364 EFI_STATUS
365 EFIAPI
PchTcoSmiOsTcoRegister(IN PCH_TCO_SMI_DISPATCH_PROTOCOL * This,IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)366 PchTcoSmiOsTcoRegister (
367   IN  PCH_TCO_SMI_DISPATCH_PROTOCOL     *This,
368   IN  PCH_TCO_SMI_DISPATCH_CALLBACK     DispatchFunction,
369   OUT EFI_HANDLE                        *DispatchHandle
370   )
371 {
372   EFI_STATUS                            Status;
373   DATABASE_RECORD                       *Record;
374 
375   //
376   // Return access denied if the SmmReadyToLock event has been triggered
377   //
378   if (mReadyToLock == TRUE) {
379     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
380     return EFI_ACCESS_DENIED;
381   }
382 
383   Status = PchSmiRecordInsert (
384              &mSrcDescOsTco,
385              (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
386              PchTcoSmiOsTcoType,
387              DispatchHandle
388              );
389   if (!EFI_ERROR (Status)) {
390     Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
391     Record->ClearSource = PchTcoSmiClearSource;
392     PchSmmClearSource (&Record->SrcDesc);
393     PchSmmEnableSource (&Record->SrcDesc);
394     SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
395   }
396   return Status;
397 }
398 
399 //
400 // Nmi
401 //
402 GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescNmi = {
403   PCH_SMM_NO_FLAGS,
404   {
405     {
406       {
407         TCO_ADDR_TYPE,
408         {R_TCO_IO_TCO1_CNT}
409       },
410       S_TCO_IO_TCO1_CNT,
411       N_TCO_IO_TCO1_CNT_NMI2SMI_EN
412     },
413     NULL_BIT_DESC_INITIALIZER
414   },
415   {
416     {
417       {
418         TCO_ADDR_TYPE,
419         {R_TCO_IO_TCO1_STS}
420       },
421       S_TCO_IO_TCO1_STS,
422       N_TCO_IO_TCO1_STS_NMI2SMI
423     }
424   },
425   //
426   // NOTE: The status of NMI2SMI won't reflect to PMC SMI_STS.
427   //       So skip the top level status check and check the TCO1_STS directly.
428   //
429   NULL_BIT_DESC_INITIALIZER
430 };
431 
432 /**
433   The register function used to register SMI handler of NMI event.
434 
435   @param[in]  This                      The pointer to the protocol itself
436   @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
437   @param[out] DispatchHandle            Handle of dispatch function to register.
438 
439   @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
440   @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
441   @retval EFI_SUCCESS                   The database record is created successfully.
442   @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
443 **/
444 EFI_STATUS
445 EFIAPI
PchTcoSmiNmiRegister(IN PCH_TCO_SMI_DISPATCH_PROTOCOL * This,IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)446 PchTcoSmiNmiRegister (
447   IN  PCH_TCO_SMI_DISPATCH_PROTOCOL     *This,
448   IN  PCH_TCO_SMI_DISPATCH_CALLBACK     DispatchFunction,
449   OUT EFI_HANDLE                        *DispatchHandle
450   )
451 {
452   EFI_STATUS                            Status;
453   DATABASE_RECORD                       *Record;
454   //
455   // Return access denied if the SmmReadyToLock event has been triggered
456   //
457   if (mReadyToLock == TRUE) {
458     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
459     return EFI_ACCESS_DENIED;
460   }
461 
462   Status = PchSmiRecordInsert (
463              &mSrcDescNmi,
464              (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
465              PchTcoSmiNmiType,
466              DispatchHandle
467              );
468   if (!EFI_ERROR (Status)) {
469     Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
470     Record->ClearSource = PchTcoSmiClearSource;
471     PchSmmClearSource (&Record->SrcDesc);
472     PchSmmEnableSource (&Record->SrcDesc);
473     SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
474   }
475   return Status;
476 }
477 
478 //
479 // IntruderDetect srcdesc
480 //
481 GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescIntruderDet = {
482   PCH_SMM_NO_FLAGS,
483   {
484     {
485       {
486         ACPI_ADDR_TYPE,
487         {R_ACPI_IO_SMI_EN}
488       },
489       S_ACPI_IO_SMI_EN,
490       N_ACPI_IO_SMI_EN_TCO
491     },
492     {
493       {
494         TCO_ADDR_TYPE,
495         {R_TCO_IO_TCO2_CNT}
496       },
497       S_TCO_IO_TCO2_CNT,
498       N_TCO_IO_TCO2_CNT_INTRD_SEL
499     }
500   },
501   {
502     {
503       {
504         TCO_ADDR_TYPE,
505         {R_TCO_IO_TCO2_STS}
506       },
507       S_TCO_IO_TCO2_STS,
508       N_TCO_IO_TCO2_STS_INTRD_DET
509     }
510   },
511   {
512     {
513       ACPI_ADDR_TYPE,
514       {R_ACPI_IO_SMI_STS}
515     },
516     S_ACPI_IO_SMI_STS,
517     N_ACPI_IO_SMI_STS_TCO
518   }
519 };
520 
521 /**
522   The register function used to register SMI handler of Intruder Detect event.
523 
524   @param[in]  This                      The pointer to the protocol itself
525   @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
526   @param[out] DispatchHandle            Handle of dispatch function to register.
527 
528   @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
529   @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
530   @retval EFI_SUCCESS                   The database record is created successfully.
531   @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
532 **/
533 EFI_STATUS
534 EFIAPI
PchTcoSmiIntruderDetRegister(IN PCH_TCO_SMI_DISPATCH_PROTOCOL * This,IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)535 PchTcoSmiIntruderDetRegister (
536   IN  PCH_TCO_SMI_DISPATCH_PROTOCOL     *This,
537   IN  PCH_TCO_SMI_DISPATCH_CALLBACK     DispatchFunction,
538   OUT EFI_HANDLE                        *DispatchHandle
539   )
540 {
541   EFI_STATUS                            Status;
542   DATABASE_RECORD                       *Record;
543 
544   //
545   // Return access denied if the SmmReadyToLock event has been triggered
546   //
547   if (mReadyToLock == TRUE) {
548     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
549     return EFI_ACCESS_DENIED;
550   }
551 
552   Status = PchSmiRecordInsert (
553              &mSrcDescIntruderDet,
554              (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
555              PchTcoSmiIntruderDetectType,
556              DispatchHandle
557              );
558   if (!EFI_ERROR (Status)) {
559     Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
560     Record->ClearSource = PchTcoSmiClearSourceAndBlock;
561     PchSmmClearSource (&Record->SrcDesc);
562     PchSmmEnableSource (&Record->SrcDesc);
563     SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
564   }
565   return Status;
566 }
567 
568 //
569 // SpiBiosWp srcdesc
570 //
571 GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescSpiBiosWp = {
572   PCH_SMM_NO_FLAGS,
573   {
574     {
575       {
576         ACPI_ADDR_TYPE,
577         {R_ACPI_IO_SMI_EN}
578       },
579       S_ACPI_IO_SMI_EN,
580       N_ACPI_IO_SMI_EN_TCO
581     },
582     {
583       {
584         PCIE_ADDR_TYPE,
585         { (
586           (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
587           (PCI_DEVICE_NUMBER_PCH_SPI << 19) |
588           (PCI_FUNCTION_NUMBER_PCH_SPI << 16) |
589           R_SPI_CFG_BC
590         ) }
591       },
592       S_SPI_CFG_BC,
593       N_SPI_CFG_BC_BLE
594     },
595   },
596   {
597     {
598       {
599         PCIE_ADDR_TYPE,
600         { (
601           (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
602           (PCI_DEVICE_NUMBER_PCH_SPI << 19) |
603           (PCI_FUNCTION_NUMBER_PCH_SPI << 16) |
604           R_SPI_CFG_BC
605         ) }
606       },
607       S_SPI_CFG_BC,
608       N_SPI_CFG_BC_SYNC_SS
609     }
610   },
611   {
612     {
613       ACPI_ADDR_TYPE,
614       {R_ACPI_IO_SMI_STS}
615     },
616     S_ACPI_IO_SMI_STS,
617     N_ACPI_IO_SMI_STS_TCO
618   }
619 };
620 
621 /**
622   Special handling for SPI Write Protect
623 
624   @param[in]  SrcDesc   Not used
625 **/
626 VOID
627 EFIAPI
PchTcoSpiWpClearSource(CONST PCH_SMM_SOURCE_DESC * SrcDesc)628 PchTcoSpiWpClearSource (
629   CONST PCH_SMM_SOURCE_DESC             *SrcDesc
630   )
631 {
632   UINT64 SpiRegBase;
633   UINT32 BiosControl;
634   UINT32 Timeout;
635 
636   SpiRegBase = SpiPciCfgBase ();
637   PciSegmentAndThenOr32 (
638     SpiRegBase + R_SPI_CFG_BC,
639     (UINT32) ~B_SPI_CFG_BC_ASYNC_SS,
640     B_SPI_CFG_BC_SYNC_SS
641     );
642   //
643   // Ensure the SYNC is cleared
644   //
645   Timeout = 1000;
646   do {
647     BiosControl = PciSegmentRead32 (SpiRegBase + R_SPI_CFG_BC);
648     Timeout--;
649   } while ((BiosControl & B_SPI_CFG_BC_SYNC_SS) && (Timeout > 0));
650 
651   //
652   // Any TCO-based status bits require special handling.
653   // SMI_STS.TCO_STS must be cleared in addition to the status bit in the TCO registers
654   //
655   PchSmmClearSource (&mDescSrcTcoSts);
656 }
657 
658 /**
659   Set SMI_EN_TCO to enable TCO SMI.
660 **/
661 STATIC
662 VOID
PchSetSmiEnTco(VOID)663 PchSetSmiEnTco (
664   VOID
665   )
666 {
667   IoOr32 (mAcpiBaseAddr + R_ACPI_IO_SMI_EN, B_ACPI_IO_SMI_EN_TCO);
668 }
669 
670 /**
671   The register function used to register SMI handler of BIOS write protect event.
672 
673   @param[in]  This                      The pointer to the protocol itself
674   @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
675   @param[out] DispatchHandle            Handle of dispatch function to register.
676 
677   @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
678   @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
679   @retval EFI_SUCCESS                   The database record is created successfully.
680   @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
681 **/
682 EFI_STATUS
683 EFIAPI
PchTcoSmiSpiBiosWpRegister(IN PCH_TCO_SMI_DISPATCH_PROTOCOL * This,IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)684 PchTcoSmiSpiBiosWpRegister (
685   IN  PCH_TCO_SMI_DISPATCH_PROTOCOL     *This,
686   IN  PCH_TCO_SMI_DISPATCH_CALLBACK     DispatchFunction,
687   OUT EFI_HANDLE                        *DispatchHandle
688   )
689 {
690   EFI_STATUS                            Status;
691   DATABASE_RECORD                       *Record;
692 
693   //
694   // Return access denied if the SmmReadyToLock event has been triggered
695   //
696   if (mReadyToLock == TRUE) {
697     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
698     return EFI_ACCESS_DENIED;
699   }
700 
701   Status = PchSmiRecordInsert (
702              &mSrcDescSpiBiosWp,
703              (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
704              PchTcoSmiSpiBiosWpType,
705              DispatchHandle
706              );
707   if (!EFI_ERROR (Status)) {
708     Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
709     Record->ClearSource = PchTcoSpiWpClearSource;
710     PchTcoSpiWpClearSource (NULL);
711     //
712     // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE.
713     // Only enable SMI_EN_TCO.
714     //
715     PchSetSmiEnTco ();
716     SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
717   }
718   return Status;
719 }
720 
721 //
722 // LpcBiosWp srcdesc
723 //
724 GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescLpcBiosWp = {
725   PCH_SMM_NO_FLAGS,
726   {
727     {
728       {
729         ACPI_ADDR_TYPE,
730         {R_ACPI_IO_SMI_EN}
731       },
732       S_ACPI_IO_SMI_EN,
733       N_ACPI_IO_SMI_EN_TCO
734     },
735     {
736       {
737         PCIE_ADDR_TYPE,
738         { (
739           (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
740           (PCI_DEVICE_NUMBER_PCH_LPC << 19) |
741           (PCI_FUNCTION_NUMBER_PCH_LPC << 16) |
742           R_LPC_CFG_BC
743         ) }
744       },
745       S_LPC_CFG_BC,
746       N_LPC_CFG_BC_LE
747     }
748   },
749   {
750     {
751       {
752         TCO_ADDR_TYPE,
753         {R_TCO_IO_TCO1_STS}
754       },
755       S_TCO_IO_TCO1_STS,
756       N_TCO_IO_TCO1_STS_BIOSWR
757     }
758   },
759   {
760     {
761       ACPI_ADDR_TYPE,
762       {R_ACPI_IO_SMI_STS}
763     },
764     S_ACPI_IO_SMI_STS,
765     N_ACPI_IO_SMI_STS_TCO
766   }
767 };
768 
769 /**
770   The register function used to register SMI handler of LPC BIOS write protect event.
771 
772   @param[in]  This                      The pointer to the protocol itself
773   @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
774   @param[out] DispatchHandle            Handle of dispatch function to register.
775 
776   @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
777   @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
778   @retval EFI_SUCCESS                   The database record is created successfully.
779   @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
780 **/
781 EFI_STATUS
782 EFIAPI
PchTcoSmiLpcBiosWpRegister(IN PCH_TCO_SMI_DISPATCH_PROTOCOL * This,IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)783 PchTcoSmiLpcBiosWpRegister (
784   IN  PCH_TCO_SMI_DISPATCH_PROTOCOL     *This,
785   IN  PCH_TCO_SMI_DISPATCH_CALLBACK     DispatchFunction,
786   OUT EFI_HANDLE                        *DispatchHandle
787   )
788 {
789   EFI_STATUS                            Status;
790   DATABASE_RECORD                       *Record;
791 
792   //
793   // Return access denied if the SmmReadyToLock event has been triggered
794   //
795   if (mReadyToLock == TRUE) {
796     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
797     return EFI_ACCESS_DENIED;
798   }
799 
800   if (IsEspiEnabled ()) {
801     //
802     // Status is D31F0's PCBC.BWPDS
803     //
804     ASSERT (FALSE);
805     return EFI_UNSUPPORTED;
806   }
807 
808   Status = PchSmiRecordInsert (
809              &mSrcDescLpcBiosWp,
810              (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
811              PchTcoSmiLpcBiosWpType,
812              DispatchHandle
813              );
814   if (!EFI_ERROR (Status)) {
815     Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
816     Record->ClearSource = PchTcoSmiClearSource;
817     PchSmmClearSource (&Record->SrcDesc);
818     //
819     // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE.
820     // Only enable SMI_EN_TCO.
821     //
822     PchSetSmiEnTco ();
823     SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
824   }
825   return Status;
826 }
827 
828 //
829 // NEWCENTURY_STS bit that needs to be cleared
830 //
831 GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescNewCentury = {
832   PCH_SMM_NO_FLAGS,
833   {
834     {
835       {
836         ACPI_ADDR_TYPE,
837         {R_ACPI_IO_SMI_EN}
838       },
839       S_ACPI_IO_SMI_EN,
840       N_ACPI_IO_SMI_EN_TCO
841     },
842     NULL_BIT_DESC_INITIALIZER
843   },
844   {
845     {
846       {
847         TCO_ADDR_TYPE,
848         {R_TCO_IO_TCO1_STS}
849       },
850       S_TCO_IO_TCO1_STS,
851       N_TCO_IO_TCO1_STS_NEWCENTURY
852     }
853   },
854   {
855     {
856       ACPI_ADDR_TYPE,
857       {R_ACPI_IO_SMI_STS}
858     },
859     S_ACPI_IO_SMI_STS,
860     N_ACPI_IO_SMI_STS_TCO
861   }
862 };
863 
864 /**
865   The register function used to register SMI handler of NEW CENTURY event.
866 
867   @param[in]  This                      The pointer to the protocol itself
868   @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
869   @param[out] DispatchHandle            Handle of dispatch function to register.
870 
871   @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
872   @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
873   @retval EFI_SUCCESS                   The database record is created successfully.
874   @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
875 **/
876 EFI_STATUS
877 EFIAPI
PchTcoSmiNewCenturyRegister(IN PCH_TCO_SMI_DISPATCH_PROTOCOL * This,IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)878 PchTcoSmiNewCenturyRegister (
879   IN  PCH_TCO_SMI_DISPATCH_PROTOCOL     *This,
880   IN  PCH_TCO_SMI_DISPATCH_CALLBACK     DispatchFunction,
881   OUT EFI_HANDLE                        *DispatchHandle
882   )
883 {
884   EFI_STATUS                            Status;
885   DATABASE_RECORD                       *Record;
886 
887   //
888   // Return access denied if the SmmReadyToLock event has been triggered
889   //
890   if (mReadyToLock == TRUE) {
891     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
892     return EFI_ACCESS_DENIED;
893   }
894 
895   Status = PchSmiRecordInsert (
896              &mSrcDescNewCentury,
897              (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
898              PchTcoSmiNewCenturyType,
899              DispatchHandle
900              );
901   if (!EFI_ERROR (Status)) {
902     Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
903     Record->ClearSource = PchTcoSmiClearSourceAndBlock;
904     PchSmmClearSource (&Record->SrcDesc);
905     PchSmmEnableSource (&Record->SrcDesc);
906     SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
907   }
908   return Status;
909 }
910 
911 /**
912   Unregister a child SMI source dispatch function with a parent SMM driver
913 
914   @param[in] This                       Protocol instance pointer.
915   @param[in] DispatchHandle             Handle of dispatch function to deregister.
916 
917   @retval EFI_SUCCESS                   The dispatch function has been successfully
918                                         unregistered and the SMI source has been disabled
919                                         if there are no other registered child dispatch
920                                         functions for this SMI source.
921   @retval EFI_INVALID_PARAMETER         Handle is invalid.
922   @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
923 **/
924 EFI_STATUS
925 EFIAPI
PchTcoSmiUnRegister(IN PCH_TCO_SMI_DISPATCH_PROTOCOL * This,IN EFI_HANDLE DispatchHandle)926 PchTcoSmiUnRegister (
927   IN  PCH_TCO_SMI_DISPATCH_PROTOCOL     *This,
928   IN  EFI_HANDLE                        DispatchHandle
929   )
930 {
931   DATABASE_RECORD                       *Record;
932   EFI_STATUS                            Status;
933 
934   Record = DATABASE_RECORD_FROM_LINK (DispatchHandle);
935   if ((Record->SrcDesc.En[1].Reg.Type == ACPI_ADDR_TYPE) &&
936       (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Dev == SpiDevNumber ()) &&
937       (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Fnc == SpiFuncNumber ()) &&
938       (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Reg == R_SPI_CFG_BC) &&
939       (Record->SrcDesc.En[1].Bit == N_SPI_CFG_BC_BLE)) {
940     //
941     // SPI Write Protect cannot be disabled
942     //
943     return EFI_ACCESS_DENIED;
944   } else if ((Record->SrcDesc.En[1].Reg.Type == ACPI_ADDR_TYPE) &&
945              (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Dev == LpcDevNumber ()) &&
946              (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Fnc == LpcFuncNumber ()) &&
947              (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Reg == R_LPC_CFG_BC) &&
948              (Record->SrcDesc.En[1].Bit == N_LPC_CFG_BC_LE)) {
949     //
950     // eSPI/LPC Write Protect cannot be disabled
951     //
952     return EFI_ACCESS_DENIED;
953   }
954 
955   Status = PchSmmCoreUnRegister (NULL, DispatchHandle);
956   if (!EFI_ERROR (Status)) {
957     SmiHandlerProfileUnregisterHandler (&gPchTcoSmiDispatchProtocolGuid, Record->Callback, NULL, 0);
958   }
959   return Status;
960 }
961 
962 
963 //
964 // PcieRpHotPlug srcdesc
965 //
966 GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC PchPcieSmiRpHotPlugTemplate = {
967   PCH_SMM_NO_FLAGS,
968   {
969     {
970       {
971         PCIE_ADDR_TYPE,
972         {R_PCH_PCIE_CFG_MPC}
973       },
974       S_PCH_PCIE_CFG_MPC,
975       N_PCH_PCIE_CFG_MPC_HPME
976     },
977     NULL_BIT_DESC_INITIALIZER
978   },
979   {
980     {
981       {
982         PCIE_ADDR_TYPE,
983         {R_PCH_PCIE_CFG_SMSCS}
984       },
985       S_PCH_PCIE_CFG_SMSCS,
986       N_PCH_PCIE_CFG_SMSCS_HPPDM
987     }
988   },
989   {
990     {
991       ACPI_ADDR_TYPE,
992       {R_ACPI_IO_SMI_STS}
993     },
994     S_ACPI_IO_SMI_STS,
995     N_ACPI_IO_SMI_STS_PCI_EXP
996   }
997 };
998 
999 /**
1000   The register function used to register SMI handler of PCIE RP hotplug event.
1001 
1002   @param[in]  This                      The pointer to the protocol itself
1003   @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
1004   @param[in]  RpIndex                   Refer PCIE_COMBINED_RPINDEX for PCH RP index and CPU RP index.
1005   @param[out] DispatchHandle            Handle of dispatch function to register.
1006 
1007   @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
1008   @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
1009   @retval EFI_SUCCESS                   The database record is created successfully.
1010   @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
1011 **/
1012 EFI_STATUS
1013 EFIAPI
PchPcieSmiHotPlugRegister(IN PCH_PCIE_SMI_DISPATCH_PROTOCOL * This,IN PCH_PCIE_SMI_RP_DISPATCH_CALLBACK DispatchFunction,IN UINTN RpIndex,OUT EFI_HANDLE * DispatchHandle)1014 PchPcieSmiHotPlugRegister (
1015   IN  PCH_PCIE_SMI_DISPATCH_PROTOCOL    *This,
1016   IN  PCH_PCIE_SMI_RP_DISPATCH_CALLBACK DispatchFunction,
1017   IN  UINTN                             RpIndex,
1018   OUT EFI_HANDLE                        *DispatchHandle
1019   )
1020 {
1021   EFI_STATUS                            Status;
1022   UINTN                                 RpDev;
1023   UINTN                                 RpFun;
1024   PCH_SMM_PCIE_REGISTER_CONTEXT         Context;
1025   DATABASE_RECORD                       *Record;
1026   //
1027   // Return access denied if the SmmReadyToLock event has been triggered
1028   //
1029   if (mReadyToLock == TRUE) {
1030     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
1031     return EFI_ACCESS_DENIED;
1032   }
1033   GetPcieRpDevFun (RpIndex, &RpDev, &RpFun);
1034 
1035   PchPcieSmiRpHotPlugTemplate.En[0].Reg.Data.pcie.Fields.Dev = (UINT8) RpDev;
1036   PchPcieSmiRpHotPlugTemplate.En[0].Reg.Data.pcie.Fields.Fnc = (UINT8) RpFun;
1037   PchPcieSmiRpHotPlugTemplate.Sts[0].Reg.Data.pcie.Fields.Dev = (UINT8) RpDev;
1038   PchPcieSmiRpHotPlugTemplate.Sts[0].Reg.Data.pcie.Fields.Fnc = (UINT8) RpFun;
1039 
1040   Status = PchSmiRecordInsert (
1041              &PchPcieSmiRpHotPlugTemplate,
1042              (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
1043              PchPcieSmiRpHotplugType,
1044              DispatchHandle
1045              );
1046   if (!EFI_ERROR (Status)) {
1047     Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
1048     Record->ChildContext.Pcie.PchSmiType = PchPcieSmiRpHotplugType;
1049     Record->ChildContext.Pcie.RpIndex = RpIndex;
1050     Record->ContextSize = sizeof (PCH_SMM_PCIE_REGISTER_CONTEXT);
1051     SmiHandlerProfileRegisterHandler (
1052       &gPchPcieSmiDispatchProtocolGuid,
1053       (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
1054       (UINTN)RETURN_ADDRESS (0),
1055       &Context,
1056       sizeof (Context)
1057       );
1058   }
1059   PchSmmClearSource (&PchPcieSmiRpHotPlugTemplate);
1060   PchSmmEnableSource (&PchPcieSmiRpHotPlugTemplate);
1061 
1062   return Status;
1063 }
1064 
1065 //
1066 // PcieRpLinkActive srcdesc
1067 //
1068 GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC PchPcieSmiRpLinkActiveTemplate = {
1069   PCH_SMM_NO_FLAGS,
1070   {
1071     {
1072       {
1073         PCIE_ADDR_TYPE,
1074         {R_PCH_PCIE_CFG_MPC}
1075       },
1076       S_PCH_PCIE_CFG_MPC,
1077       N_PCH_PCIE_CFG_MPC_HPME
1078     },
1079     NULL_BIT_DESC_INITIALIZER
1080   },
1081   {
1082     {
1083       {
1084         PCIE_ADDR_TYPE,
1085         {R_PCH_PCIE_CFG_SMSCS}
1086       },
1087       S_PCH_PCIE_CFG_SMSCS,
1088       N_PCH_PCIE_CFG_SMSCS_HPLAS
1089     }
1090   },
1091   {
1092     {
1093       ACPI_ADDR_TYPE,
1094       {R_ACPI_IO_SMI_STS}
1095     },
1096     S_ACPI_IO_SMI_STS,
1097     N_ACPI_IO_SMI_STS_PCI_EXP
1098   }
1099 };
1100 
1101 /**
1102   The register function used to register SMI handler of PCIE RP link active event.
1103 
1104   @param[in]  This                      The pointer to the protocol itself
1105   @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
1106   @param[in]  RpIndex                   Refer PCIE_COMBINED_RPINDEX for PCH RP index and CPU RP index.
1107   @param[out] DispatchHandle            Handle of dispatch function to register.
1108 
1109   @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
1110   @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
1111   @retval EFI_SUCCESS                   The database record is created successfully.
1112   @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
1113 **/
1114 EFI_STATUS
1115 EFIAPI
PchPcieSmiLinkActiveRegister(IN PCH_PCIE_SMI_DISPATCH_PROTOCOL * This,IN PCH_PCIE_SMI_RP_DISPATCH_CALLBACK DispatchFunction,IN UINTN RpIndex,OUT EFI_HANDLE * DispatchHandle)1116 PchPcieSmiLinkActiveRegister (
1117   IN  PCH_PCIE_SMI_DISPATCH_PROTOCOL    *This,
1118   IN  PCH_PCIE_SMI_RP_DISPATCH_CALLBACK DispatchFunction,
1119   IN  UINTN                             RpIndex,
1120   OUT EFI_HANDLE                        *DispatchHandle
1121   )
1122 {
1123   EFI_STATUS                            Status;
1124   UINTN                                 RpDev;
1125   UINTN                                 RpFun;
1126   PCH_SMM_PCIE_REGISTER_CONTEXT         Context;
1127   DATABASE_RECORD                       *Record;
1128   //
1129   // Return access denied if the SmmReadyToLock event has been triggered
1130   //
1131   if (mReadyToLock == TRUE) {
1132     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
1133     return EFI_ACCESS_DENIED;
1134   }
1135 
1136   GetPcieRpDevFun (RpIndex, &RpDev, &RpFun);
1137 
1138 
1139   PchPcieSmiRpLinkActiveTemplate.En[0].Reg.Data.pcie.Fields.Dev = (UINT8) RpDev;
1140   PchPcieSmiRpLinkActiveTemplate.En[0].Reg.Data.pcie.Fields.Fnc = (UINT8) RpFun;
1141   PchPcieSmiRpLinkActiveTemplate.Sts[0].Reg.Data.pcie.Fields.Dev = (UINT8) RpDev;
1142   PchPcieSmiRpLinkActiveTemplate.Sts[0].Reg.Data.pcie.Fields.Fnc = (UINT8) RpFun;
1143 
1144   Status = PchSmiRecordInsert (
1145              &PchPcieSmiRpLinkActiveTemplate,
1146              (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
1147              PchPcieSmiRpLinkActiveType,
1148              DispatchHandle
1149              );
1150   if (!EFI_ERROR (Status)) {
1151     Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
1152     Record->ChildContext.Pcie.PchSmiType = PchPcieSmiRpLinkActiveType;
1153     Record->ChildContext.Pcie.RpIndex = RpIndex;
1154     Record->ContextSize = sizeof (PCH_SMM_PCIE_REGISTER_CONTEXT);
1155     SmiHandlerProfileRegisterHandler (
1156       &gPchPcieSmiDispatchProtocolGuid,
1157       (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
1158       (UINTN)RETURN_ADDRESS (0),
1159       &Context,
1160       sizeof (Context)
1161       );
1162   }
1163   PchSmmClearSource (&PchPcieSmiRpLinkActiveTemplate);
1164   PchSmmEnableSource (&PchPcieSmiRpLinkActiveTemplate);
1165 
1166   return Status;
1167 }
1168 
1169 //
1170 // PcieRpLinkEq srcdesc
1171 //
1172 GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC PchPcieSmiRpLinkEqTemplate = {
1173   PCH_SMM_NO_FLAGS,
1174   {
1175     {
1176       {
1177         PCIE_ADDR_TYPE,
1178         {R_PCH_PCIE_CFG_EQCFG1}
1179       },
1180       S_PCH_PCIE_CFG_EQCFG1,
1181       N_PCH_PCIE_CFG_EQCFG1_LERSMIE
1182     },
1183     NULL_BIT_DESC_INITIALIZER
1184   },
1185   {
1186     {
1187       {
1188         PCIE_ADDR_TYPE,
1189         {R_PCH_PCIE_CFG_SMSCS}
1190       },
1191       S_PCH_PCIE_CFG_SMSCS,
1192       N_PCH_PCIE_CFG_SMSCS_LERSMIS
1193     }
1194   },
1195   {
1196     {
1197       ACPI_ADDR_TYPE,
1198       {R_ACPI_IO_SMI_STS}
1199     },
1200     S_ACPI_IO_SMI_STS,
1201     N_ACPI_IO_SMI_STS_PCI_EXP
1202   }
1203 };
1204 /**
1205   The register function used to register SMI handler of PCIE RP Link Equalization Request event.
1206 
1207   @param[in]  This                      The pointer to the protocol itself
1208   @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
1209   @param[in]  RpIndex                   Refer PCIE_COMBINED_RPINDEX for PCH RP index and CPU RP index.
1210   @param[out] DispatchHandle            Handle of dispatch function to register.
1211 
1212   @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
1213   @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
1214   @retval EFI_SUCCESS                   The database record is created successfully.
1215   @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
1216 **/
1217 EFI_STATUS
1218 EFIAPI
PchPcieSmiLinkEqRegister(IN PCH_PCIE_SMI_DISPATCH_PROTOCOL * This,IN PCH_PCIE_SMI_RP_DISPATCH_CALLBACK DispatchFunction,IN UINTN RpIndex,OUT EFI_HANDLE * DispatchHandle)1219 PchPcieSmiLinkEqRegister (
1220   IN  PCH_PCIE_SMI_DISPATCH_PROTOCOL    *This,
1221   IN  PCH_PCIE_SMI_RP_DISPATCH_CALLBACK DispatchFunction,
1222   IN  UINTN                             RpIndex,
1223   OUT EFI_HANDLE                        *DispatchHandle
1224   )
1225 {
1226   UINTN                                 RpDev;
1227   UINTN                                 RpFun;
1228   EFI_STATUS                            Status;
1229   PCH_SMM_PCIE_REGISTER_CONTEXT         Context;
1230   DATABASE_RECORD                       *Record;
1231 
1232   //
1233   // Return access denied if the SmmReadyToLock event has been triggered
1234   //
1235   if (mReadyToLock == TRUE) {
1236     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
1237     return EFI_ACCESS_DENIED;
1238   }
1239 
1240   GetPcieRpDevFun (RpIndex, &RpDev, &RpFun);
1241 
1242   //
1243   // Patch the RP device number and function number of srcdesc.
1244   //
1245   PchPcieSmiRpLinkEqTemplate.En[0].Reg.Data.pcie.Fields.Dev = (UINT8) RpDev;
1246   PchPcieSmiRpLinkEqTemplate.En[0].Reg.Data.pcie.Fields.Fnc = (UINT8) RpFun;
1247   PchPcieSmiRpLinkEqTemplate.Sts[0].Reg.Data.pcie.Fields.Dev = (UINT8) RpDev;
1248   PchPcieSmiRpLinkEqTemplate.Sts[0].Reg.Data.pcie.Fields.Fnc = (UINT8) RpFun;
1249 
1250   Status = PchSmiRecordInsert (
1251            &PchPcieSmiRpLinkEqTemplate,
1252            (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
1253            PchPcieSmiRpLinkEqType,
1254            DispatchHandle
1255            );
1256   if (!EFI_ERROR (Status)) {
1257     Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
1258     Record->ChildContext.Pcie.PchSmiType = PchPcieSmiRpLinkEqType;
1259     Record->ChildContext.Pcie.RpIndex = RpIndex;
1260     Record->ContextSize = sizeof (PCH_SMM_PCIE_REGISTER_CONTEXT);
1261     SmiHandlerProfileRegisterHandler (
1262       &gPchPcieSmiDispatchProtocolGuid,
1263       (EFI_SMM_HANDLER_ENTRY_POINT2) DispatchFunction,
1264       (UINTN)RETURN_ADDRESS (0),
1265       &Context,
1266       sizeof (Context)
1267       );
1268   }
1269   return Status;
1270 }
1271 
1272 /**
1273   Unregister a child SMI source dispatch function with a parent SMM driver
1274 
1275   @param[in] This                       Protocol instance pointer.
1276   @param[in] DispatchHandle             Handle of dispatch function to deregister.
1277 
1278   @retval EFI_SUCCESS                   The dispatch function has been successfully
1279                                         unregistered and the SMI source has been disabled
1280                                         if there are no other registered child dispatch
1281                                         functions for this SMI source.
1282   @retval EFI_INVALID_PARAMETER         Handle is invalid.
1283   @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
1284 **/
1285 EFI_STATUS
1286 EFIAPI
PchPcieSmiUnRegister(IN PCH_PCIE_SMI_DISPATCH_PROTOCOL * This,IN EFI_HANDLE DispatchHandle)1287 PchPcieSmiUnRegister (
1288   IN  PCH_PCIE_SMI_DISPATCH_PROTOCOL    *This,
1289   IN  EFI_HANDLE                        DispatchHandle
1290   )
1291 {
1292   DATABASE_RECORD                       *RecordToDelete;
1293   EFI_STATUS                            Status;
1294 
1295   RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);
1296   Status = PchSmmCoreUnRegister (NULL, DispatchHandle);
1297   if (!EFI_ERROR (Status)) {
1298       SmiHandlerProfileUnregisterHandler (
1299         &gPchPcieSmiDispatchProtocolGuid,
1300         RecordToDelete->Callback,
1301         &RecordToDelete->ChildContext,
1302         sizeof (RecordToDelete->ContextSize)
1303         );
1304   }
1305   return Status;
1306 }
1307 
1308 //
1309 // Pme srcdesc
1310 //
1311 GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescPme = {
1312   PCH_SMM_SCI_EN_DEPENDENT,
1313   {
1314     {
1315       {
1316         ACPI_ADDR_TYPE,
1317         {R_ACPI_IO_GPE0_EN_127_96}
1318       },
1319       S_ACPI_IO_GPE0_EN_127_96,
1320       N_ACPI_IO_GPE0_EN_127_96_PME
1321     },
1322     NULL_BIT_DESC_INITIALIZER
1323   },
1324   {
1325     {
1326       {
1327         ACPI_ADDR_TYPE,
1328         {R_ACPI_IO_GPE0_STS_127_96}
1329       },
1330       S_ACPI_IO_GPE0_STS_127_96,
1331       N_ACPI_IO_GPE0_STS_127_96_PME
1332     }
1333   },
1334   {
1335     {
1336       ACPI_ADDR_TYPE,
1337       {R_ACPI_IO_SMI_STS}
1338     },
1339     S_ACPI_IO_SMI_STS,
1340     N_ACPI_IO_SMI_STS_GPE0
1341   }
1342 };
1343 
1344 /**
1345   The register function used to register SMI handler of PME event.
1346 
1347   @param[in]  This                      The pointer to the protocol itself
1348   @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
1349   @param[out] DispatchHandle            Handle of dispatch function to register.
1350 
1351   @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
1352   @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
1353   @retval EFI_SUCCESS                   The database record is created successfully.
1354   @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
1355 **/
1356 EFI_STATUS
1357 EFIAPI
PchAcpiSmiPmeRegister(IN PCH_ACPI_SMI_DISPATCH_PROTOCOL * This,IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)1358 PchAcpiSmiPmeRegister (
1359   IN  PCH_ACPI_SMI_DISPATCH_PROTOCOL    *This,
1360   IN  PCH_ACPI_SMI_DISPATCH_CALLBACK    DispatchFunction,
1361   OUT EFI_HANDLE                        *DispatchHandle
1362   )
1363 {
1364   EFI_STATUS                            Status;
1365 
1366   //
1367   // Return access denied if the SmmReadyToLock event has been triggered
1368   //
1369   if (mReadyToLock == TRUE) {
1370     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
1371     return EFI_ACCESS_DENIED;
1372   }
1373 
1374   Status = PchSmiRecordInsert (
1375              &mSrcDescPme,
1376              (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
1377              PchAcpiSmiPmeType,
1378              DispatchHandle
1379              );
1380   PchSmmClearSource (&mSrcDescPme);
1381   PchSmmEnableSource (&mSrcDescPme);
1382   if (!EFI_ERROR (Status)) {
1383     SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
1384   }
1385   return Status;
1386 }
1387 
1388 //
1389 // PmeB0 srcdesc
1390 //
1391 GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescPmeB0 = {
1392   PCH_SMM_SCI_EN_DEPENDENT,
1393   {
1394     {
1395       {
1396         ACPI_ADDR_TYPE,
1397         {R_ACPI_IO_GPE0_EN_127_96}
1398       },
1399       S_ACPI_IO_GPE0_EN_127_96,
1400       N_ACPI_IO_GPE0_EN_127_96_PME_B0
1401     },
1402     NULL_BIT_DESC_INITIALIZER
1403   },
1404   {
1405     {
1406       {
1407         ACPI_ADDR_TYPE,
1408         {R_ACPI_IO_GPE0_STS_127_96}
1409       },
1410       S_ACPI_IO_GPE0_STS_127_96,
1411       N_ACPI_IO_GPE0_STS_127_96_PME_B0
1412     }
1413   },
1414   {
1415     {
1416       ACPI_ADDR_TYPE,
1417       {R_ACPI_IO_SMI_STS}
1418     },
1419     S_ACPI_IO_SMI_STS,
1420     N_ACPI_IO_SMI_STS_GPE0
1421   }
1422 };
1423 /**
1424   The register function used to register SMI handler of PME B0 event.
1425 
1426   @param[in]  This                      The pointer to the protocol itself
1427   @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
1428   @param[out] DispatchHandle            Handle of dispatch function to register.
1429 
1430   @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
1431   @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
1432   @retval EFI_SUCCESS                   The database record is created successfully.
1433   @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
1434 **/
1435 EFI_STATUS
1436 EFIAPI
PchAcpiSmiPmeB0Register(IN PCH_ACPI_SMI_DISPATCH_PROTOCOL * This,IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)1437 PchAcpiSmiPmeB0Register (
1438   IN  PCH_ACPI_SMI_DISPATCH_PROTOCOL    *This,
1439   IN  PCH_ACPI_SMI_DISPATCH_CALLBACK    DispatchFunction,
1440   OUT EFI_HANDLE                        *DispatchHandle
1441   )
1442 {
1443   EFI_STATUS                            Status;
1444 
1445   //
1446   // Return access denied if the SmmReadyToLock event has been triggered
1447   //
1448   if (mReadyToLock == TRUE) {
1449     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
1450     return EFI_ACCESS_DENIED;
1451   }
1452 
1453   Status = PchSmiRecordInsert (
1454              &mSrcDescPmeB0,
1455              (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
1456              PchAcpiSmiPmeB0Type,
1457              DispatchHandle
1458              );
1459   PchSmmClearSource (&mSrcDescPmeB0);
1460   PchSmmEnableSource (&mSrcDescPmeB0);
1461   if (!EFI_ERROR (Status)) {
1462     SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
1463   }
1464   return Status;
1465 }
1466 
1467 //
1468 // RtcAlarm srcdesc
1469 //
1470 GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescRtcAlarm = {
1471   PCH_SMM_SCI_EN_DEPENDENT,
1472   {
1473     {
1474       {
1475         ACPI_ADDR_TYPE,
1476         {R_ACPI_IO_PM1_EN}
1477       },
1478       S_ACPI_IO_PM1_EN,
1479       N_ACPI_IO_PM1_EN_RTC
1480     },
1481     NULL_BIT_DESC_INITIALIZER
1482   },
1483   {
1484     {
1485       {
1486         ACPI_ADDR_TYPE,
1487         {R_ACPI_IO_PM1_STS}
1488       },
1489       S_ACPI_IO_PM1_STS,
1490       N_ACPI_IO_PM1_STS_RTC
1491     }
1492   },
1493   {
1494     {
1495       ACPI_ADDR_TYPE,
1496       {R_ACPI_IO_SMI_STS}
1497     },
1498     S_ACPI_IO_SMI_STS,
1499     N_ACPI_IO_SMI_STS_PM1_STS_REG
1500   }
1501 };
1502 
1503 /**
1504   The register function used to register SMI handler of RTC alarm event.
1505 
1506   @param[in]  This                      The pointer to the protocol itself
1507   @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
1508   @param[out] DispatchHandle            Handle of dispatch function to register.
1509 
1510   @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
1511   @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
1512   @retval EFI_SUCCESS                   The database record is created successfully.
1513   @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
1514 **/
1515 EFI_STATUS
1516 EFIAPI
PchAcpiSmiRtcAlarmRegister(IN PCH_ACPI_SMI_DISPATCH_PROTOCOL * This,IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)1517 PchAcpiSmiRtcAlarmRegister (
1518   IN  PCH_ACPI_SMI_DISPATCH_PROTOCOL    *This,
1519   IN  PCH_ACPI_SMI_DISPATCH_CALLBACK    DispatchFunction,
1520   OUT EFI_HANDLE                        *DispatchHandle
1521   )
1522 {
1523   EFI_STATUS                            Status;
1524 
1525   //
1526   // Return access denied if the SmmReadyToLock event has been triggered
1527   //
1528   if (mReadyToLock == TRUE) {
1529     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
1530     return EFI_ACCESS_DENIED;
1531   }
1532 
1533   Status = PchSmiRecordInsert (
1534              &mSrcDescRtcAlarm,
1535              (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
1536              PchAcpiSmiRtcAlarmType,
1537              DispatchHandle
1538              );
1539 
1540   PchSmmClearSource (&mSrcDescRtcAlarm);
1541   PchSmmEnableSource (&mSrcDescRtcAlarm);
1542   if (!EFI_ERROR (Status)) {
1543     SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
1544   }
1545   return Status;
1546 }
1547 
1548 //
1549 // TmrOverflow srcdesc
1550 //
1551 GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescTmrOverflow = {
1552   PCH_SMM_SCI_EN_DEPENDENT,
1553   {
1554     {
1555       {
1556         ACPI_ADDR_TYPE,
1557         {R_ACPI_IO_PM1_EN}
1558       },
1559       S_ACPI_IO_PM1_EN,
1560       N_ACPI_IO_PM1_EN_TMROF
1561     },
1562     NULL_BIT_DESC_INITIALIZER
1563   },
1564   {
1565     {
1566       {
1567         ACPI_ADDR_TYPE,
1568         {R_ACPI_IO_PM1_STS}
1569       },
1570       S_ACPI_IO_PM1_STS,
1571       N_ACPI_IO_PM1_STS_TMROF
1572     }
1573   },
1574   {
1575     {
1576       ACPI_ADDR_TYPE,
1577       {R_ACPI_IO_SMI_STS}
1578     },
1579     S_ACPI_IO_SMI_STS,
1580     N_ACPI_IO_SMI_STS_PM1_STS_REG
1581   }
1582 };
1583 
1584 /**
1585   The register function used to register SMI handler of Timer Overflow event.
1586 
1587   @param[in]  This                      The pointer to the protocol itself
1588   @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
1589   @param[out] DispatchHandle            Handle of dispatch function to register.
1590 
1591   @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
1592   @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
1593   @retval EFI_SUCCESS                   The database record is created successfully.
1594   @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
1595 **/
1596 EFI_STATUS
1597 EFIAPI
PchAcpiSmiTmrOverflowRegister(IN PCH_ACPI_SMI_DISPATCH_PROTOCOL * This,IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)1598 PchAcpiSmiTmrOverflowRegister (
1599   IN  PCH_ACPI_SMI_DISPATCH_PROTOCOL    *This,
1600   IN  PCH_ACPI_SMI_DISPATCH_CALLBACK    DispatchFunction,
1601   OUT EFI_HANDLE                        *DispatchHandle
1602   )
1603 {
1604   EFI_STATUS                            Status;
1605 
1606   //
1607   // Return access denied if the SmmReadyToLock event has been triggered
1608   //
1609   if (mReadyToLock == TRUE) {
1610     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
1611     return EFI_ACCESS_DENIED;
1612   }
1613 
1614   Status = PchSmiRecordInsert (
1615              &mSrcDescTmrOverflow,
1616              (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
1617              PchAcpiSmiTmrOverflowType,
1618              DispatchHandle
1619              );
1620   PchSmmClearSource (&mSrcDescTmrOverflow);
1621   PchSmmEnableSource (&mSrcDescTmrOverflow);
1622   if (!EFI_ERROR (Status)) {
1623     SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
1624   }
1625 
1626   return Status;
1627 }
1628 
1629 /**
1630   Unregister a child SMI source dispatch function with a parent SMM driver
1631 
1632   @param[in] This                       Protocol instance pointer.
1633   @param[in] DispatchHandle             Handle of dispatch function to deregister.
1634 
1635   @retval EFI_SUCCESS                   The dispatch function has been successfully
1636                                         unregistered and the SMI source has been disabled
1637                                         if there are no other registered child dispatch
1638                                         functions for this SMI source.
1639   @retval EFI_INVALID_PARAMETER         Handle is invalid.
1640   @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
1641 **/
1642 EFI_STATUS
1643 EFIAPI
PchAcpiSmiUnRegister(IN PCH_ACPI_SMI_DISPATCH_PROTOCOL * This,IN EFI_HANDLE DispatchHandle)1644 PchAcpiSmiUnRegister (
1645   IN  PCH_ACPI_SMI_DISPATCH_PROTOCOL    *This,
1646   IN  EFI_HANDLE                        DispatchHandle
1647   )
1648 {
1649   DATABASE_RECORD                   *RecordToDelete;
1650   EFI_STATUS                        Status;
1651 
1652   RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);
1653   Status = PchSmmCoreUnRegister (NULL, DispatchHandle);
1654   if (!EFI_ERROR (Status)) {
1655     SmiHandlerProfileUnregisterHandler (&gPchAcpiSmiDispatchProtocolGuid, RecordToDelete->Callback, NULL, 0);
1656   }
1657   return Status;
1658 }
1659 
1660 //
1661 // SerialIrq srcdesc
1662 //
1663 GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescSerialIrq = {
1664   PCH_SMM_NO_FLAGS,
1665   {
1666     NULL_BIT_DESC_INITIALIZER,
1667     NULL_BIT_DESC_INITIALIZER
1668   },
1669   {
1670     {
1671       {
1672         ACPI_ADDR_TYPE,
1673         {R_ACPI_IO_SMI_STS}
1674       },
1675       S_ACPI_IO_SMI_STS,
1676       N_ACPI_IO_SMI_STS_SERIRQ
1677     }
1678   },
1679   {
1680     {
1681       ACPI_ADDR_TYPE,
1682       {R_ACPI_IO_SMI_STS}
1683     },
1684     S_ACPI_IO_SMI_STS,
1685     N_ACPI_IO_SMI_STS_SERIRQ
1686   }
1687 };
1688 
1689 /**
1690   The register function used to register SMI handler of Serial IRQ event.
1691 
1692   @param[in]  This                      The pointer to the protocol itself
1693   @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
1694   @param[out] DispatchHandle            Handle of dispatch function to register.
1695 
1696   @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
1697   @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
1698   @retval EFI_SUCCESS                   The database record is created successfully.
1699   @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
1700 **/
1701 EFI_STATUS
1702 EFIAPI
PchSmiSerialIrqRegister(IN PCH_SMI_DISPATCH_PROTOCOL * This,IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)1703 PchSmiSerialIrqRegister (
1704   IN  PCH_SMI_DISPATCH_PROTOCOL         *This,
1705   IN  PCH_SMI_DISPATCH_CALLBACK         DispatchFunction,
1706   OUT EFI_HANDLE                        *DispatchHandle
1707   )
1708 {
1709   EFI_STATUS                            Status;
1710 
1711   //
1712   // Return access denied if the SmmReadyToLock event has been triggered
1713   //
1714   if (mReadyToLock == TRUE) {
1715     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
1716     return EFI_ACCESS_DENIED;
1717   }
1718 
1719   Status = PchSmiRecordInsert (
1720              &mSrcDescSerialIrq,
1721              (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
1722              PchSmiSerialIrqType,
1723              DispatchHandle
1724              );
1725   PchSmmClearSource (&mSrcDescSerialIrq);
1726   PchSmmEnableSource (&mSrcDescSerialIrq);
1727   if (!EFI_ERROR (Status)) {
1728      SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
1729   }
1730   return Status;
1731 }
1732 
1733 //
1734 // McSmi srcdesc
1735 //
1736 GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescMcSmi = {
1737   PCH_SMM_NO_FLAGS,
1738   {
1739     {
1740       {
1741         ACPI_ADDR_TYPE,
1742         {R_ACPI_IO_SMI_EN}
1743       },
1744       S_ACPI_IO_SMI_EN,
1745       N_ACPI_IO_SMI_EN_MCSMI
1746     },
1747     NULL_BIT_DESC_INITIALIZER
1748   },
1749   {
1750     {
1751       {
1752         ACPI_ADDR_TYPE,
1753         {R_ACPI_IO_SMI_STS}
1754       },
1755       S_ACPI_IO_SMI_STS,
1756       N_ACPI_IO_SMI_STS_MCSMI
1757     }
1758   },
1759   {
1760     {
1761       ACPI_ADDR_TYPE,
1762       {R_ACPI_IO_SMI_STS}
1763     },
1764     S_ACPI_IO_SMI_STS,
1765     N_ACPI_IO_SMI_STS_MCSMI
1766   }
1767 };
1768 
1769 /**
1770   The register function used to register SMI handler of MCSMI event.
1771 
1772   @param[in]  This                      The pointer to the protocol itself
1773   @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
1774   @param[out] DispatchHandle            Handle of dispatch function to register.
1775 
1776   @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
1777   @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
1778   @retval EFI_SUCCESS                   The database record is created successfully.
1779   @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
1780 **/
1781 EFI_STATUS
1782 EFIAPI
PchSmiMcSmiRegister(IN PCH_SMI_DISPATCH_PROTOCOL * This,IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)1783 PchSmiMcSmiRegister (
1784   IN  PCH_SMI_DISPATCH_PROTOCOL         *This,
1785   IN  PCH_SMI_DISPATCH_CALLBACK         DispatchFunction,
1786   OUT EFI_HANDLE                        *DispatchHandle
1787   )
1788 {
1789   EFI_STATUS                            Status;
1790 
1791   //
1792   // Return access denied if the SmmReadyToLock event has been triggered
1793   //
1794   if (mReadyToLock == TRUE) {
1795     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
1796     return EFI_ACCESS_DENIED;
1797   }
1798 
1799   Status = PchSmiRecordInsert (
1800              &mSrcDescMcSmi,
1801              (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
1802              PchSmiMcSmiType,
1803              DispatchHandle
1804              );
1805   PchSmmClearSource (&mSrcDescMcSmi);
1806   PchSmmEnableSource (&mSrcDescMcSmi);
1807   if (!EFI_ERROR (Status)) {
1808     SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
1809   }
1810   return Status;
1811 }
1812 
1813 //
1814 // SmBus srcdesc
1815 //
1816 GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescSmbus = {
1817   PCH_SMM_NO_FLAGS,
1818   {
1819     NULL_BIT_DESC_INITIALIZER,
1820     NULL_BIT_DESC_INITIALIZER
1821   },
1822   {
1823     {
1824       {
1825         ACPI_ADDR_TYPE,
1826         {R_ACPI_IO_SMI_STS}
1827       },
1828       S_ACPI_IO_SMI_STS,
1829       N_ACPI_IO_SMI_STS_SMBUS
1830     }
1831   },
1832   {
1833     {
1834       ACPI_ADDR_TYPE,
1835       {R_ACPI_IO_SMI_STS}
1836     },
1837     S_ACPI_IO_SMI_STS,
1838     N_ACPI_IO_SMI_STS_SMBUS
1839   }
1840 };
1841 
1842 /**
1843   The register function used to register SMI handler of SMBUS event.
1844 
1845   @param[in]  This                      The pointer to the protocol itself
1846   @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
1847   @param[out] DispatchHandle            Handle of dispatch function to register.
1848 
1849   @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
1850   @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
1851   @retval EFI_SUCCESS                   The database record is created successfully.
1852   @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
1853 **/
1854 EFI_STATUS
1855 EFIAPI
PchSmiSmbusRegister(IN PCH_SMI_DISPATCH_PROTOCOL * This,IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)1856 PchSmiSmbusRegister (
1857   IN  PCH_SMI_DISPATCH_PROTOCOL         *This,
1858   IN  PCH_SMI_DISPATCH_CALLBACK         DispatchFunction,
1859   OUT EFI_HANDLE                        *DispatchHandle
1860   )
1861 {
1862   EFI_STATUS                            Status;
1863 
1864   //
1865   // Return access denied if the SmmReadyToLock event has been triggered
1866   //
1867   if (mReadyToLock == TRUE) {
1868     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
1869     return EFI_ACCESS_DENIED;
1870   }
1871 
1872   Status = PchSmiRecordInsert (
1873              &mSrcDescSmbus,
1874              (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
1875              PchSmiSmBusType,
1876              DispatchHandle
1877              );
1878   PchSmmClearSource (&mSrcDescSmbus);
1879   PchSmmEnableSource (&mSrcDescSmbus);
1880   if (!EFI_ERROR (Status)) {
1881     SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
1882   }
1883   return Status;
1884 }
1885 
1886 //
1887 // SpiAsyncSmi srcdesc
1888 //
1889 GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescSpiAsyncSmi = {
1890   PCH_SMM_NO_FLAGS,
1891   {
1892     {
1893       {
1894         PCIE_ADDR_TYPE,
1895         { (
1896           (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
1897           (PCI_DEVICE_NUMBER_PCH_SPI << 19) |
1898           (PCI_FUNCTION_NUMBER_PCH_SPI << 16) |
1899           R_SPI_CFG_BC
1900         ) }
1901       },
1902       S_SPI_CFG_BC,
1903       N_SPI_CFG_BC_ASE_BWP
1904     },
1905     NULL_BIT_DESC_INITIALIZER
1906   },
1907   {
1908     {
1909       {
1910         PCIE_ADDR_TYPE,
1911         { (
1912           (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
1913           (PCI_DEVICE_NUMBER_PCH_SPI << 19) |
1914           (PCI_FUNCTION_NUMBER_PCH_SPI << 16) |
1915           R_SPI_CFG_BC
1916         ) }
1917       },
1918       S_SPI_CFG_BC,
1919       N_SPI_CFG_BC_ASYNC_SS
1920     }
1921   },
1922   {
1923     {
1924       ACPI_ADDR_TYPE,
1925       {R_ACPI_IO_SMI_STS}
1926     },
1927     S_ACPI_IO_SMI_STS,
1928     N_ACPI_IO_SMI_STS_SPI
1929   }
1930 };
1931 
1932 /**
1933   Special handling for SPI Asynchronous SMI.
1934   If SPI ASYNC SMI is enabled, De-assert SMI is sent when Flash Cycle Done
1935   transitions from 1 to 0 or when the SMI enable becomes false.
1936 
1937   @param[in]  SrcDesc   Not used
1938 **/
1939 VOID
1940 EFIAPI
PchSmiSpiAsyncClearSource(CONST PCH_SMM_SOURCE_DESC * SrcDesc)1941 PchSmiSpiAsyncClearSource (
1942   CONST PCH_SMM_SOURCE_DESC             *SrcDesc
1943   )
1944 {
1945   UINT64                                SpiRegBase;
1946   UINT32                                SpiBar0;
1947 
1948   SpiRegBase = SpiPciCfgBase ();
1949   SpiBar0 = PciSegmentRead32 (SpiRegBase + R_SPI_CFG_BAR0) & ~(B_SPI_CFG_BAR0_MASK);
1950   if (SpiBar0 != PCH_SPI_BASE_ADDRESS) {
1951     //
1952     // Temporary disable MSE, and override with SPI reserved MMIO address, then enable MSE.
1953     //
1954     SpiBar0 = PCH_SPI_BASE_ADDRESS;
1955     PciSegmentAnd8 (SpiRegBase + PCI_COMMAND_OFFSET, (UINT8) ~EFI_PCI_COMMAND_MEMORY_SPACE);
1956     PciSegmentWrite32 (SpiRegBase + R_SPI_CFG_BAR0, SpiBar0);
1957     PciSegmentOr8 (SpiRegBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE);
1958   }
1959 
1960   MmioOr32 (SpiBar0 + R_SPI_MEM_HSFSC, B_SPI_MEM_HSFSC_FDONE);
1961 }
1962 
1963 /**
1964   Special handling to enable SPI Asynchronous SMI
1965 **/
1966 VOID
PchSmiSpiAsyncEnableSource(VOID)1967 PchSmiSpiAsyncEnableSource (
1968   VOID
1969   )
1970 {
1971   UINT64 SpiRegBase;
1972   UINT32 Data32And;
1973   UINT32 Data32Or;
1974 
1975   SpiRegBase = SpiPciCfgBase ();
1976   Data32And = (UINT32) ~B_SPI_CFG_BC_SYNC_SS;
1977   Data32Or = B_SPI_CFG_BC_ASE_BWP;
1978 
1979   PciSegmentAndThenOr32 (
1980     SpiRegBase + R_SPI_CFG_BC,
1981     Data32And,
1982     Data32Or
1983     );
1984   S3BootScriptSavePciCfgReadWrite (
1985     S3BootScriptWidthUint32,
1986     SpiRegBase + R_SPI_CFG_BC,
1987     (VOID*) &Data32Or,
1988     (VOID*) &Data32And
1989     );
1990 
1991   //
1992   // Clear the source
1993   //
1994   PchSmiSpiAsyncClearSource (NULL);
1995 }
1996 
1997 /**
1998   The register function used to register SMI handler of SPI Asynchronous event.
1999 
2000   @param[in]  This                      The pointer to the protocol itself
2001   @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
2002   @param[out] DispatchHandle            Handle of dispatch function to register.
2003 
2004   @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
2005   @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
2006   @retval EFI_SUCCESS                   The database record is created successfully.
2007   @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
2008 **/
2009 EFI_STATUS
2010 EFIAPI
PchSmiSpiAsyncRegister(IN PCH_SMI_DISPATCH_PROTOCOL * This,IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction,OUT EFI_HANDLE * DispatchHandle)2011 PchSmiSpiAsyncRegister (
2012   IN  PCH_SMI_DISPATCH_PROTOCOL         *This,
2013   IN  PCH_SMI_DISPATCH_CALLBACK         DispatchFunction,
2014   OUT EFI_HANDLE                        *DispatchHandle
2015   )
2016 {
2017   EFI_STATUS                            Status;
2018   DATABASE_RECORD                       *Record;
2019 
2020   //
2021   // Return access denied if the SmmReadyToLock event has been triggered
2022   //
2023   if (mReadyToLock == TRUE) {
2024     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
2025     return EFI_ACCESS_DENIED;
2026   }
2027 
2028   Status = PchSmiRecordInsert (
2029              &mSrcDescSpiAsyncSmi,
2030              (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
2031              PchSmiSpiAsyncType,
2032              DispatchHandle
2033              );
2034 
2035   if (!EFI_ERROR (Status)) {
2036     Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
2037     Record->ClearSource = PchSmiSpiAsyncClearSource;
2038     PchSmiSpiAsyncClearSource (NULL);
2039     PchSmiSpiAsyncEnableSource ();
2040     SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, (UINTN)RETURN_ADDRESS (0), NULL, 0);
2041   }
2042   return Status;
2043 }
2044 
2045 /**
2046   Unregister a child SMI source dispatch function with a parent SMM driver
2047 
2048   @param[in] This                       Protocol instance pointer.
2049   @param[in] DispatchHandle             Handle of dispatch function to deregister.
2050 
2051   @retval EFI_SUCCESS                   The dispatch function has been successfully
2052                                         unregistered and the SMI source has been disabled
2053                                         if there are no other registered child dispatch
2054                                         functions for this SMI source.
2055   @retval EFI_INVALID_PARAMETER         Handle is invalid.
2056   @retval EFI_ACCESS_DENIED             Return access denied if the SmmReadyToLock event has been triggered
2057   @retval EFI_ACCESS_DENIED             Return access denied since SPI aync SMI handler is not able to disabled.
2058 **/
2059 EFI_STATUS
2060 EFIAPI
PchSmiUnRegister(IN PCH_SMI_DISPATCH_PROTOCOL * This,IN EFI_HANDLE DispatchHandle)2061 PchSmiUnRegister (
2062   IN  PCH_SMI_DISPATCH_PROTOCOL         *This,
2063   IN  EFI_HANDLE                        DispatchHandle
2064   )
2065 {
2066   DATABASE_RECORD                       *Record;
2067   UINT64                                SpiRegBase;
2068   EFI_STATUS                            Status;
2069 
2070   Record = DATABASE_RECORD_FROM_LINK (DispatchHandle);
2071   if ((Record->SrcDesc.En[0].Reg.Type == PCIE_ADDR_TYPE) &&
2072       (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Dev == SpiDevNumber ()) &&
2073       (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Fnc == SpiFuncNumber ()) &&
2074       (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Reg == R_SPI_CFG_BC) &&
2075       (Record->SrcDesc.En[0].Bit == N_SPI_CFG_BC_ASE_BWP)) {
2076     SpiRegBase = SpiPciCfgBase ();
2077     if (PciSegmentRead8 (SpiRegBase + R_SPI_CFG_BC) & B_SPI_CFG_BC_BILD) {
2078       //
2079       // SPI Asynchronous SMI cannot be disabled
2080       //
2081       return EFI_ACCESS_DENIED;
2082     }
2083   }
2084   Status = PchSmmCoreUnRegister (NULL, DispatchHandle);
2085   if (!EFI_ERROR (Status)) {
2086     SmiHandlerProfileUnregisterHandler (&gPchSmiDispatchProtocolGuid, Record->Callback, NULL, 0);
2087   }
2088   return Status;
2089 }
2090 
2091 
2092 /**
2093   Declaration of PCH TCO SMI DISPATCH PROTOCOL instance
2094 **/
2095 PCH_TCO_SMI_DISPATCH_PROTOCOL mPchTcoSmiDispatchProtocol = {
2096   PCH_TCO_SMI_DISPATCH_REVISION,        // Revision
2097   PchTcoSmiUnRegister,                  // Unregister
2098   PchTcoSmiMchRegister,                 // Mch
2099   PchTcoSmiTcoTimeoutRegister,          // TcoTimeout
2100   PchTcoSmiOsTcoRegister,               // OsTco
2101   PchTcoSmiNmiRegister,                 // Nmi
2102   PchTcoSmiIntruderDetRegister,         // IntruderDectect
2103   PchTcoSmiSpiBiosWpRegister,           // SpiBiosWp
2104   PchTcoSmiLpcBiosWpRegister,           // LpcBiosWp
2105   PchTcoSmiNewCenturyRegister           // NewCentury
2106 };
2107 
2108 /**
2109   Declaration of PCH PCIE SMI DISPATCH PROTOCOL instance
2110 **/
2111 PCH_PCIE_SMI_DISPATCH_PROTOCOL mPchPcieSmiDispatchProtocol = {
2112   PCH_PCIE_SMI_DISPATCH_REVISION,       // Revision
2113   PchPcieSmiUnRegister,                 // Unregister
2114   PchPcieSmiHotPlugRegister,            // PcieRpXHotPlug
2115   PchPcieSmiLinkActiveRegister,         // PcieRpXLinkActive
2116   PchPcieSmiLinkEqRegister              // PcieRpXLinkEq
2117 };
2118 
2119 /**
2120   Declaration of PCH ACPI SMI DISPATCH PROTOCOL instance
2121 **/
2122 PCH_ACPI_SMI_DISPATCH_PROTOCOL mPchAcpiSmiDispatchProtocol = {
2123   PCH_ACPI_SMI_DISPATCH_REVISION,       // Revision
2124   PchAcpiSmiUnRegister,                 // Unregister
2125   PchAcpiSmiPmeRegister,                // Pme
2126   PchAcpiSmiPmeB0Register,              // PmeB0
2127   PchAcpiSmiRtcAlarmRegister,           // RtcAlarm
2128   PchAcpiSmiTmrOverflowRegister         // TmrOverflow
2129 };
2130 
2131 /**
2132   Declaration of MISC PCH SMI DISPATCH PROTOCOL instance
2133 **/
2134 PCH_SMI_DISPATCH_PROTOCOL mPchSmiDispatchProtocol = {
2135   PCH_SMI_DISPATCH_REVISION,            // Revision
2136   PchSmiUnRegister,                     // Unregister
2137   PchSmiSerialIrqRegister,              // SerialIrq
2138   PchSmiMcSmiRegister,                  // McSmi
2139   PchSmiSmbusRegister,                  // SmBus
2140   PchSmiSpiAsyncRegister                // SpiAsync
2141 };
2142 
2143 /**
2144   Install protocols of PCH specifics SMI types, including
2145   PCH TCO SMI types, PCH PCIE SMI types, PCH ACPI SMI types, PCH MISC SMI types.
2146 
2147   @retval                               the result of protocol installation
2148 **/
2149 EFI_STATUS
InstallPchSmiDispatchProtocols(VOID)2150 InstallPchSmiDispatchProtocols (
2151   VOID
2152   )
2153 {
2154   EFI_HANDLE                            Handle;
2155   EFI_STATUS                            Status;
2156 
2157   Handle = NULL;
2158   Status = gSmst->SmmInstallProtocolInterface (
2159                     &Handle,
2160                     &gPchTcoSmiDispatchProtocolGuid,
2161                     EFI_NATIVE_INTERFACE,
2162                     &mPchTcoSmiDispatchProtocol
2163                     );
2164   Status = gSmst->SmmInstallProtocolInterface (
2165                     &Handle,
2166                     &gPchPcieSmiDispatchProtocolGuid,
2167                     EFI_NATIVE_INTERFACE,
2168                     &mPchPcieSmiDispatchProtocol
2169                     );
2170   Status = gSmst->SmmInstallProtocolInterface (
2171                     &Handle,
2172                     &gPchAcpiSmiDispatchProtocolGuid,
2173                     EFI_NATIVE_INTERFACE,
2174                     &mPchAcpiSmiDispatchProtocol
2175                     );
2176   Status = gSmst->SmmInstallProtocolInterface (
2177                     &Handle,
2178                     &gPchSmiDispatchProtocolGuid,
2179                     EFI_NATIVE_INTERFACE,
2180                     &mPchSmiDispatchProtocol
2181                     );
2182 
2183   return Status;
2184 }
2185 
2186 /**
2187   The function to dispatch all callback function of PCH SMI types.
2188 
2189   @retval EFI_SUCCESS                   Function successfully completed
2190   @retval EFI_UNSUPPORTED               no
2191 **/
2192 EFI_STATUS
PchSmiTypeCallbackDispatcher(IN DATABASE_RECORD * Record)2193 PchSmiTypeCallbackDispatcher (
2194   IN  DATABASE_RECORD                   *Record
2195   )
2196 {
2197   EFI_STATUS                            Status;
2198   PCH_SMI_TYPES                         PchSmiType;
2199   UINTN                                 RpIndex;
2200   PCH_PCIE_SMI_RP_CONTEXT               RpContext;
2201 
2202   PchSmiType = Record->PchSmiType;
2203   Status     = EFI_SUCCESS;
2204 
2205   switch (PchSmiType) {
2206     case PchTcoSmiMchType:
2207     case PchTcoSmiTcoTimeoutType:
2208     case PchTcoSmiOsTcoType:
2209     case PchTcoSmiNmiType:
2210     case PchTcoSmiIntruderDetectType:
2211     case PchTcoSmiSpiBiosWpType:
2212     case PchTcoSmiLpcBiosWpType:
2213     case PchTcoSmiNewCenturyType:
2214       ((PCH_TCO_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI_HANDLE)&Record->Link);
2215       break;
2216     case PchPcieSmiRpHotplugType:
2217     case PchPcieSmiRpLinkActiveType:
2218     case PchPcieSmiRpLinkEqType:
2219       RpContext.BusNum  = DEFAULT_PCI_BUS_NUMBER_PCH;
2220       RpContext.DevNum  = (UINT8) Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Dev;
2221       RpContext.FuncNum = (UINT8) Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Fnc;
2222       GetPcieRpNumber (RpContext.DevNum, RpContext.FuncNum, &RpIndex);
2223       RpContext.RpIndex = (UINT8) RpIndex;
2224       ((PCH_PCIE_SMI_RP_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI_HANDLE)&Record->Link, &RpContext);
2225       break;
2226     case PchAcpiSmiPmeType:
2227     case PchAcpiSmiPmeB0Type:
2228     case PchAcpiSmiRtcAlarmType:
2229     case PchAcpiSmiTmrOverflowType:
2230       ((PCH_ACPI_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI_HANDLE)&Record->Link);
2231       break;
2232     case PchEspiSmiEspiSlaveType:
2233       ((PCH_ESPI_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI_HANDLE)&Record->Link);
2234       break;
2235     case PchSmiSerialIrqType:
2236     case PchSmiMcSmiType:
2237     case PchSmiSmBusType:
2238     case PchSmiSpiAsyncType:
2239     case PchIoTrapSmiType:                ///< internal type for IoTrap
2240       ((PCH_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) ((EFI_HANDLE)&Record->Link);
2241       break;
2242     default:
2243       Status = EFI_UNSUPPORTED;
2244       break;
2245   }
2246 
2247   return Status;
2248 }
2249 
2250 GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC mSrcDescIoTrap[4] = {
2251   //
2252   // PCH I/O Trap register 0 monitor
2253   //
2254   {
2255     PCH_SMM_NO_FLAGS,
2256     {
2257       {
2258         {
2259           PCR_ADDR_TYPE,
2260           {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG0) }
2261         },
2262         4,
2263         0
2264       },
2265       NULL_BIT_DESC_INITIALIZER
2266     },
2267     {
2268       {
2269         {
2270           PCR_ADDR_TYPE,
2271           {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) }
2272         },
2273         1,
2274         0
2275       }
2276     },
2277     {
2278       {
2279         ACPI_ADDR_TYPE,
2280         {R_ACPI_IO_SMI_STS}
2281       },
2282       S_ACPI_IO_SMI_STS,
2283       N_ACPI_IO_SMI_STS_MONITOR
2284     }
2285   },
2286   //
2287   // PCH I/O Trap register 1 monitor
2288   //
2289   {
2290     PCH_SMM_NO_FLAGS,
2291     {
2292       {
2293         {
2294           PCR_ADDR_TYPE,
2295           {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG1) }
2296         },
2297         4,
2298         0
2299       },
2300       NULL_BIT_DESC_INITIALIZER
2301     },
2302     {
2303       {
2304         {
2305           PCR_ADDR_TYPE,
2306           {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) }
2307         },
2308         1,
2309         1
2310       }
2311     },
2312     {
2313       {
2314         ACPI_ADDR_TYPE,
2315         {R_ACPI_IO_SMI_STS}
2316       },
2317       S_ACPI_IO_SMI_STS,
2318       N_ACPI_IO_SMI_STS_MONITOR
2319     }
2320   },
2321   //
2322   // PCH I/O Trap register 2 monitor
2323   //
2324   {
2325     PCH_SMM_NO_FLAGS,
2326     {
2327       {
2328         {
2329           PCR_ADDR_TYPE,
2330           {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG2) }
2331         },
2332         4,
2333         0
2334       },
2335       NULL_BIT_DESC_INITIALIZER
2336     },
2337     {
2338       {
2339         {
2340           PCR_ADDR_TYPE,
2341           {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) }
2342         },
2343         1,
2344         2
2345       }
2346     },
2347     {
2348       {
2349         ACPI_ADDR_TYPE,
2350         {R_ACPI_IO_SMI_STS}
2351       },
2352       S_ACPI_IO_SMI_STS,
2353       N_ACPI_IO_SMI_STS_MONITOR
2354     }
2355   },
2356   //
2357   // PCH I/O Trap register 3 monitor,
2358   //
2359   {
2360     PCH_SMM_NO_FLAGS,
2361     {
2362       {
2363         {
2364           PCR_ADDR_TYPE,
2365           {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG3) }
2366         },
2367         4,
2368         0
2369       },
2370       NULL_BIT_DESC_INITIALIZER
2371     },
2372     {
2373       {
2374         {
2375           PCR_ADDR_TYPE,
2376           {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) }
2377         },
2378         1,
2379         3
2380       }
2381     },
2382     {
2383       {
2384         ACPI_ADDR_TYPE,
2385         {R_ACPI_IO_SMI_STS}
2386       },
2387       S_ACPI_IO_SMI_STS,
2388       N_ACPI_IO_SMI_STS_MONITOR
2389     }
2390   }
2391 };
2392 
2393 /**
2394   The register function used to register SMI handler of IoTrap event.
2395   This is internal function and only used by Iotrap module.
2396 
2397   @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
2398   @param[in]  IoTrapIndex               Index number of IOTRAP register
2399   @param[out] DispatchHandle            Handle of dispatch function to register.
2400 
2401   @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
2402   @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
2403   @retval EFI_SUCCESS                   The database record is created successfully.
2404 **/
2405 EFI_STATUS
PchInternalIoTrapSmiRegister(IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction,IN UINTN IoTrapIndex,OUT EFI_HANDLE * DispatchHandle)2406 PchInternalIoTrapSmiRegister (
2407   IN  PCH_SMI_DISPATCH_CALLBACK         DispatchFunction,
2408   IN  UINTN                             IoTrapIndex,
2409   OUT EFI_HANDLE                        *DispatchHandle
2410   )
2411 {
2412   EFI_STATUS                            Status;
2413 
2414   Status = PchSmiRecordInsert (
2415              &mSrcDescIoTrap[IoTrapIndex],
2416              (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
2417              PchIoTrapSmiType,
2418              DispatchHandle
2419              );
2420   PchSmmClearSource (&mSrcDescIoTrap[IoTrapIndex]);
2421   PchSmmEnableSource (&mSrcDescIoTrap[IoTrapIndex]);
2422   return Status;
2423 }
2424 
2425 /**
2426   Unregister a child SMI source dispatch function with a parent SMM driver
2427 
2428   @param[in] DispatchHandle             Handle of dispatch function to deregister.
2429 
2430   @retval EFI_SUCCESS                   The dispatch function has been successfully
2431                                         unregistered and the SMI source has been disabled
2432                                         if there are no other registered child dispatch
2433                                         functions for this SMI source.
2434   @retval EFI_INVALID_PARAMETER         Handle is invalid.
2435 **/
2436 EFI_STATUS
PchInternalIoTrapSmiUnRegister(IN EFI_HANDLE DispatchHandle)2437 PchInternalIoTrapSmiUnRegister (
2438   IN  EFI_HANDLE                        DispatchHandle
2439   )
2440 {
2441   return PchSmmCoreUnRegister (NULL, DispatchHandle);
2442 }
2443