1 /** @file
2   Prototypes and defines for the PCH SMM Dispatcher.
3 
4 Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 #ifndef PCH_SMM_H
9 #define PCH_SMM_H
10 
11 #include <Uefi.h>
12 #include <Protocol/PciRootBridgeIo.h>
13 #include <Protocol/LoadedImage.h>
14 #include <Protocol/SmmControl2.h>
15 #include <Protocol/SmmUsbDispatch2.h>
16 #include <Protocol/SmmSxDispatch2.h>
17 #include <Protocol/SmmSwDispatch2.h>
18 #include <Protocol/SmmGpiDispatch2.h>
19 #include <Protocol/SmmPowerButtonDispatch2.h>
20 #include <Protocol/SmmPeriodicTimerDispatch2.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 #include <Library/DxeServicesTableLib.h>
23 #include <Library/DebugLib.h>
24 #include <Library/IoLib.h>
25 #include <Library/BaseLib.h>
26 #include <Library/BaseMemoryLib.h>
27 #include <Library/DevicePathLib.h>
28 #include <Library/SmmServicesTableLib.h>
29 #include <Library/ReportStatusCodeLib.h>
30 #include <Library/PerformanceLib.h>
31 #include <Protocol/SmmReadyToLock.h>
32 #include <IndustryStandard/Pci30.h>
33 #include <PchAccess.h>
34 #include <Library/PchCycleDecodingLib.h>
35 #include <Library/PchPcieRpLib.h>
36 #include <Library/PchPcrLib.h>
37 #include <Library/MmPciLib.h>
38 #include <Library/GpioLib.h>
39 #include <Library/PchInfoLib.h>
40 #include <Library/PchEspiLib.h>
41 #include <Library/GpioPrivateLib.h>
42 #include <Protocol/PchTcoSmiDispatch.h>
43 #include <Protocol/PchPcieSmiDispatch.h>
44 #include <Protocol/PchAcpiSmiDispatch.h>
45 #include <Protocol/PchGpioUnlockSmiDispatch.h>
46 #include <Protocol/PchSmiDispatch.h>
47 #include <Protocol/PchEspiSmiDispatch.h>
48 #include "IoTrap.h"
49 
50 #include <Library/SmiHandlerProfileLib.h>
51 
52 #define EFI_BAD_POINTER          0xAFAFAFAFAFAFAFAFULL
53 
54 extern BOOLEAN                   mReadyToLock;
55 
56 ///
57 /// Define an enumeration for all the supported protocols
58 ///
59 #define PCH_SMM_PROTOCOL_TYPE_MAX       6
60 
61 typedef enum {
62   UsbType,
63   SxType,
64   SwType,
65   GpiType,
66   PowerButtonType,
67   PeriodicTimerType,
68   PchSmiDispatchType,
69   PchSmmProtocolTypeMax
70 } PCH_SMM_PROTOCOL_TYPE;
71 
72 ///
73 /// Define all the supported types of PCH SMI
74 ///
75 typedef enum {
76   PchTcoSmiMchType,
77   PchTcoSmiTcoTimeoutType,
78   PchTcoSmiOsTcoType,
79   PchTcoSmiNmiType,
80   PchTcoSmiIntruderDetectType,
81   PchTcoSmiSpiBiosWpType,
82   PchTcoSmiLpcBiosWpType,
83   PchTcoSmiNewCenturyType,
84   PchPcieSmiRpHotplugType,
85   PchPcieSmiRpLinkActiveType,
86   PchPcieSmiRpLinkEqType,
87   PchAcpiSmiPmeType,
88   PchAcpiSmiPmeB0Type,
89   PchAcpiSmiRtcAlarmType,
90   PchAcpiSmiTmrOverflowType,
91   PchGpioUnlockSmiType,
92   PchEspiSmiEspiSlaveType,
93   PchSmiSerialIrqType,
94   PchSmiMcSmiType,
95   PchSmiSmBusType,
96   PchSmiSpiAsyncType,
97   PchIoTrapSmiType                      ///< internal SMI type
98 } PCH_SMI_TYPES;
99 
100 ///
101 /// Generic funciton pointer to cover all Pch SMI function pointer types
102 ///
103 typedef
104 VOID
105 (EFIAPI *PCH_SMI_CALLBACK_FUNCTIONS) (
106   IN EFI_HANDLE                         DispatchHandle,
107   ...
108   );
109 
110 
111 ///
112 /// SPECIFYING A REGISTER
113 /// We want a general way of referring to addresses.  For this case, we'll only
114 /// need addresses in the ACPI table (and the TCO entries within the ACPI table).
115 /// However, it's interesting to consider what it would take to support other types
116 /// of addresses.  To address Will's concern, I think it prudent to accommodate it
117 /// early on in the design.
118 ///
119 /// Addresses we need to consider:
120 ///
121 ///  Type:                           Required:
122 ///  I/O                             Yes
123 ///    ACPI (special case of I/O)    Only if we want to
124 ///    TCO  (special case of I/O)    Only if we want to
125 ///  GPIO  (special case of MMIO)    Only if we want to
126 ///  Memory (or Memory Mapped I/O)   Only if we want to
127 ///  PCIE                            Yes, for BiosWp
128 ///
129 typedef enum {
130   ///
131   ///  IO_ADDR_TYPE, /// unimplemented
132   ///
133   ACPI_ADDR_TYPE,
134   TCO_ADDR_TYPE,
135   ///
136   ///  MEMORY_ADDR_TYPE, /// unimplemented
137   ///
138   GPIO_ADDR_TYPE,
139   MEMORY_MAPPED_IO_ADDRESS_TYPE,
140   PCIE_ADDR_TYPE,
141   PCR_ADDR_TYPE,
142   NUM_ADDR_TYPES,                     ///< count of items in this enum
143   PCH_SMM_ADDR_TYPE_NULL        = -1  ///< sentinel to indicate NULL or to signal end of arrays
144 } ADDR_TYPE;
145 
146 //
147 // Assumption: 32-bits -- enum's evaluate to integer
148 // Assumption: This code will only run on IA-32.  Justification: IA-64 doesn't have SMIs.
149 // We don't have to worry about 64-bit addresses.
150 // Typedef the size of addresses in case the numbers I'm using are wrong or in case
151 // this changes.  This is a good idea because PCI_ADDR will change, for example, when
152 // we add support for PciExpress.
153 //
154 typedef UINT16 IO_ADDR;
155 typedef IO_ADDR ACPI_ADDR;  ///< can omit
156 typedef IO_ADDR TCO_ADDR;   ///< can omit
157 typedef UINTN MEM_ADDR;
158 typedef MEM_ADDR *MEMORY_MAPPED_IO_ADDRESS;
159 typedef MEM_ADDR *GPIO_ADDR;
160 typedef union {
161   UINT32  Raw;
162   struct {
163     UINT32 Reg: 16;
164     UINT32 Fnc: 3;
165     UINT32 Dev: 5;
166     UINT32 Bus: 8;
167   } Fields;
168 } PCIE_ADDR;
169 
170 typedef union {
171   UINT32  Raw;
172   struct {
173     UINT16 Offset;
174     UINT8  Pid;
175     UINT8  Base;
176   } Fields;
177 } PCR_ADDR;
178 
179 typedef struct {
180   ADDR_TYPE Type;
181   union {
182     ///
183     /// used to initialize during declaration/definition
184     ///
185     UINT32                    raw;
186 
187     ///
188     /// used to access useful data
189     ///
190     IO_ADDR                   io;
191     ACPI_ADDR                 acpi;
192     TCO_ADDR                  tco;
193     GPIO_ADDR                 gpio;
194     MEM_ADDR                  mem;
195     MEMORY_MAPPED_IO_ADDRESS  Mmio;
196     PCIE_ADDR                 pcie;
197     PCR_ADDR                  Pcr;
198 
199   } Data;
200 
201 } PCH_SMM_ADDRESS;
202 
203 ///
204 /// SPECIFYING BITS WITHIN A REGISTER
205 /// Here's a struct that helps us specify a source or enable bit.
206 ///
207 typedef struct {
208   PCH_SMM_ADDRESS Reg;
209   UINT8           SizeInBytes;  ///< of the register
210   UINT8           Bit;
211 } PCH_SMM_BIT_DESC;
212 
213 //
214 // Sometimes, we'll have bit descriptions that are unused.  It'd be great to have a
215 // way to easily identify them:
216 //
217 #define IS_BIT_DESC_NULL(BitDesc)   ((BitDesc).Reg.Type == PCH_SMM_ADDR_TYPE_NULL)  ///< "returns" true when BitDesc is NULL
218 #define NULL_THIS_BIT_DESC(BitDesc) ((BitDesc).Reg.Type = PCH_SMM_ADDR_TYPE_NULL)   ///< will "return" an integer w/ value of 0
219 #define NULL_BIT_DESC_INITIALIZER \
220   { \
221     { \
222       PCH_SMM_ADDR_TYPE_NULL, \
223       { \
224         0 \
225       } \
226     }, \
227     0, 0 \
228   }
229 //
230 // I'd like a type to specify the callback's Sts & En bits because they'll
231 // be commonly used together:
232 //
233 #define NUM_EN_BITS   2
234 #define NUM_STS_BITS  1
235 
236 //
237 // Flags
238 //
239 typedef UINT8 PCH_SMM_SOURCE_FLAGS;
240 
241 //
242 // Flags required to describe the event source
243 //
244 #define PCH_SMM_NO_FLAGS          0
245 #define PCH_SMM_SCI_EN_DEPENDENT  1
246 
247 typedef struct {
248   PCH_SMM_SOURCE_FLAGS  Flags;
249   PCH_SMM_BIT_DESC      En[NUM_EN_BITS];    ///< Describes the enable bit(s) for the SMI event
250   PCH_SMM_BIT_DESC      Sts[NUM_STS_BITS];  ///< Describes the secondary status bit for the SMI event. Might be the same as TopLevelSmi
251   PCH_SMM_BIT_DESC      PmcSmiSts;          ///< Refereing to the top level status bit in PMC SMI_STS, i.e. R_PCH_SMI_STS
252 } PCH_SMM_SOURCE_DESC;
253 
254 ///
255 /// Used to initialize null source descriptor
256 ///
257 #define NULL_SOURCE_DESC_INITIALIZER \
258   { \
259     PCH_SMM_NO_FLAGS, \
260     { \
261       NULL_BIT_DESC_INITIALIZER, NULL_BIT_DESC_INITIALIZER \
262     }, \
263     { \
264       NULL_BIT_DESC_INITIALIZER \
265     }, \
266     NULL_BIT_DESC_INITIALIZER \
267   }
268 
269 ///
270 /// CHILD CONTEXTS
271 /// To keep consistent w/ the architecture, we'll need to provide the context
272 /// to the child when we call its callback function.  After talking with Will,
273 /// we agreed that we'll need functions to "dig" the context out of the hardware
274 /// in many cases (Sx, Trap, Gpi, etc), and we'll need a function to compare those
275 /// contexts to prevent unnecessary dispatches.  I'd like a general type for these
276 /// "GetContext" functions, so I'll need a union of all the protocol contexts for
277 /// our internal use:
278 ///
279 typedef union {
280   //
281   // (in no particular order)
282   //
283   EFI_SMM_SX_REGISTER_CONTEXT             Sx;
284   EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT PeriodicTimer;
285   EFI_SMM_SW_REGISTER_CONTEXT             Sw;
286   EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT   PowerButton;
287   EFI_SMM_USB_REGISTER_CONTEXT            Usb;
288   EFI_SMM_GPI_REGISTER_CONTEXT            Gpi;
289 } PCH_SMM_CONTEXT;
290 
291 ///
292 /// Misc data for PchDispatcher usage.
293 /// For PeriodicTimer, since the ElapsedTime is removed from EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT of EDKII,
294 /// and PchDispatcher needs it for every record. Thus move it here to support ElapsedTime.
295 ///
296 typedef union {
297   UINTN ElapsedTime;
298 } PCH_SMM_MISC_DATA;
299 
300 //
301 // Assumption: PeriodicTimer largest at 3x64-bits or 24 bytes
302 //
303 typedef struct _DATABASE_RECORD DATABASE_RECORD;
304 
305 ///
306 /// Assumption: the GET_CONTEXT function will be as small and simple as possible.
307 /// Assumption: We don't need to pass in an enumeration for the protocol because each
308 ///    GET_CONTEXT function is written for only one protocol.
309 /// We also need a function to compare contexts to see if the child should be dispatched
310 /// In addition, we need a function to acquire CommBuffer and CommBufferSize for
311 ///    dispatch callback function of EDKII native support.
312 ///
313 typedef
314 VOID
315 (EFIAPI *GET_CONTEXT) (
316   IN  DATABASE_RECORD    * Record,
317   OUT PCH_SMM_CONTEXT    * Context
318   );
319 
320 typedef
321 BOOLEAN
322 (EFIAPI *CMP_CONTEXT) (
323   IN PCH_SMM_CONTEXT     * Context1,
324   IN PCH_SMM_CONTEXT     * Context2
325   );
326 
327 typedef
328 VOID
329 (EFIAPI *GET_COMMBUFFER) (
330   IN  DATABASE_RECORD    * Record,
331   OUT VOID               **CommBuffer,
332   OUT UINTN              * CommBufferSize
333   );
334 
335 ///
336 /// Finally, every protocol will require a "Get Context" and "Compare Context" call, so
337 /// we may as well wrap that up in a table, too.
338 ///
339 typedef struct {
340   GET_CONTEXT     GetContext;
341   CMP_CONTEXT     CmpContext;
342   GET_COMMBUFFER  GetCommBuffer;
343 } CONTEXT_FUNCTIONS;
344 
345 extern CONTEXT_FUNCTIONS          ContextFunctions[PCH_SMM_PROTOCOL_TYPE_MAX];
346 
347 ///
348 /// MAPPING CONTEXT TO BIT DESCRIPTIONS
349 /// I'd like to have a general approach to mapping contexts to bit descriptions.
350 /// Sometimes, we'll find that we can use table lookups or constant assignments;
351 /// other times, we'll find that we'll need to use a function to perform the mapping.
352 /// If we define a macro to mask that process, we'll never have to change the code.
353 /// I don't know if this is desirable or not -- if it isn't, then we can get rid
354 /// of the macros and just use function calls or variable assignments.  Doesn't matter
355 /// to me.
356 /// Mapping complex contexts requires a function
357 ///
358 
359 /**
360   Maps a USB context to a source description.
361 
362   @param[in] Context              The context we need to map.  Type must be USB.
363   @param[out] SrcDesc             The source description that corresponds to the given context.
364 
365 **/
366 VOID
367 MapUsbToSrcDesc (
368   IN  PCH_SMM_CONTEXT         *Context,
369   OUT PCH_SMM_SOURCE_DESC     *SrcDesc
370   );
371 
372 /**
373   Figure out which timer the child is requesting and
374   send back the source description
375 
376   @param[in] DispatchContext      The pointer to the Dispatch Context instances
377   @param[out] SrcDesc             The pointer to the source description
378 
379 **/
380 VOID
381 MapPeriodicTimerToSrcDesc (
382   IN  PCH_SMM_CONTEXT                                         *DispatchContext,
383   OUT PCH_SMM_SOURCE_DESC                                     *SrcDesc
384   );
385 
386 //
387 // Mapping simple contexts can be done by assignment or lookup table
388 //
389 extern CONST PCH_SMM_SOURCE_DESC  SW_SOURCE_DESC;
390 extern CONST PCH_SMM_SOURCE_DESC  SX_SOURCE_DESC;
391 extern CONST PCH_SMM_SOURCE_DESC  POWER_BUTTON_SOURCE_DESC;
392 
393 //
394 // With the changes we've made to the protocols, we can now use table
395 // lookups for the following protocols:
396 //
397 extern CONST PCH_SMM_SOURCE_DESC  PCH_GPI_SOURCE_DESC_TEMPLATE;
398 
399 ///
400 /// For PCHx, APMC is UINT8 port, so the MAX SWI Value is 0xFF.
401 ///
402 #define MAXIMUM_SWI_VALUE 0xFF
403 ///
404 /// Open: Need to make sure this kind of type cast will actually work.
405 ///   May need an intermediate form w/ two VOID* arguments.  I'll figure
406 ///   that out when I start compiling.
407 ///
408 typedef
409 VOID
410 (EFIAPI *PCH_SMM_CLEAR_SOURCE) (
411   PCH_SMM_SOURCE_DESC * SrcDesc
412   );
413 
414 ///
415 /// "DATABASE" RECORD
416 /// Linked list data structures
417 ///
418 #define DATABASE_RECORD_SIGNATURE SIGNATURE_32 ('D', 'B', 'R', 'C')
419 
420 struct _DATABASE_RECORD {
421   UINT32                        Signature;
422   LIST_ENTRY                    Link;
423   BOOLEAN                       Processed;
424   ///
425   /// Status and Enable bit description
426   ///
427   PCH_SMM_SOURCE_DESC           SrcDesc;
428 
429   ///
430   /// Callback function
431   ///
432   EFI_SMM_HANDLER_ENTRY_POINT2  Callback;
433   PCH_SMM_CONTEXT               ChildContext;
434 
435   ///
436   /// Special handling hooks -- init them to NULL if unused/unneeded
437   ///
438   PCH_SMM_CLEAR_SOURCE          ClearSource;  ///< needed for SWSMI timer
439 
440   ///
441   /// Functions required to make callback code general
442   ///
443   CONTEXT_FUNCTIONS             ContextFunctions;
444 
445   ///
446   /// The protocol that this record dispatches
447   ///
448   PCH_SMM_PROTOCOL_TYPE         ProtocolType;
449   EFI_GUID                      *ProtocolGuid;
450 
451   ///
452   /// Misc data for private usage
453   ///
454   PCH_SMM_MISC_DATA             MiscData;
455 
456   ///
457   /// PCH SMI callback function
458   ///
459   PCH_SMI_CALLBACK_FUNCTIONS    PchSmiCallback;
460   ///
461   /// Indicate the PCH SMI types.
462   ///
463   PCH_SMI_TYPES                 PchSmiType;
464 };
465 
466 #define DATABASE_RECORD_FROM_LINK(_record)  CR (_record, DATABASE_RECORD, Link, DATABASE_RECORD_SIGNATURE)
467 #define DATABASE_RECORD_FROM_CHILDCONTEXT(_record)  CR (_record, DATABASE_RECORD, ChildContext, DATABASE_RECORD_SIGNATURE)
468 
469 ///
470 /// HOOKING INTO THE ARCHITECTURE
471 ///
472 typedef
473 EFI_STATUS
474 (EFIAPI *PCH_SMM_GENERIC_REGISTER) (
475   IN  VOID                                    **This,
476   IN  VOID                                    *DispatchFunction,
477   IN  VOID                                    *DispatchContext,
478   OUT EFI_HANDLE                              *DispatchHandle
479   );
480 typedef
481 EFI_STATUS
482 (EFIAPI *PCH_SMM_GENERIC_UNREGISTER) (
483   IN  VOID                                    **This,
484   IN  EFI_HANDLE                              DispatchHandle
485   );
486 
487 ///
488 /// Define a memory "stamp" equivalent in size and function to most of the protocols
489 ///
490 typedef struct {
491   PCH_SMM_GENERIC_REGISTER    Register;
492   PCH_SMM_GENERIC_UNREGISTER  Unregister;
493   UINTN                       Extra1;
494   UINTN                       Extra2; ///< may not need this one
495 } PCH_SMM_GENERIC_PROTOCOL;
496 
497 /**
498   Register a child SMI dispatch function with a parent SMM driver.
499 
500   @param[in] This                 Pointer to the PCH_SMM_GENERIC_PROTOCOL instance.
501   @param[in] DispatchFunction     Pointer to dispatch function to be invoked for this SMI source.
502   @param[in] DispatchContext      Pointer to the dispatch function's context.
503   @param[out] DispatchHandle      Handle of dispatch function, for when interfacing
504                                   with the parent SMM driver, will be the address of linked
505                                   list link in the call back record.
506 
507   @retval EFI_OUT_OF_RESOURCES    Insufficient resources to create database record
508   @retval EFI_INVALID_PARAMETER   The input parameter is invalid
509   @retval EFI_SUCCESS             The dispatch function has been successfully
510                                   registered and the SMI source has been enabled.
511 **/
512 EFI_STATUS
513 EFIAPI
514 PchSmmCoreRegister (
515   IN  PCH_SMM_GENERIC_PROTOCOL                          *This,
516   IN  EFI_SMM_HANDLER_ENTRY_POINT2                      DispatchFunction,
517   IN  PCH_SMM_CONTEXT                                   *DispatchContext,
518   OUT EFI_HANDLE                                        *DispatchHandle
519   );
520 
521 /**
522   Unregister a child SMI source dispatch function with a parent SMM driver.
523 
524   @param[in] This                 Pointer to the PCH_SMM_GENERIC_PROTOCOL instance.
525   @param[in] DispatchHandle       Handle of dispatch function to deregister.
526 
527   @retval EFI_SUCCESS             The dispatch function has been successfully
528                                   unregistered and the SMI source has been disabled
529                                   if there are no other registered child dispatch
530                                   functions for this SMI source.
531   @retval EFI_INVALID_PARAMETER   Handle is invalid.
532 **/
533 EFI_STATUS
534 EFIAPI
535 PchSmmCoreUnRegister (
536   IN  PCH_SMM_GENERIC_PROTOCOL                         *This,
537   IN  EFI_HANDLE                                       *DispatchHandle
538   );
539 
540 typedef union {
541   PCH_SMM_GENERIC_PROTOCOL                    Generic;
542   EFI_SMM_USB_DISPATCH2_PROTOCOL              Usb;
543   EFI_SMM_SX_DISPATCH2_PROTOCOL               Sx;
544   EFI_SMM_SW_DISPATCH2_PROTOCOL               Sw;
545   EFI_SMM_GPI_DISPATCH2_PROTOCOL              Gpi;
546   EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL     PowerButton;
547   EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL   PeriodicTimer;
548 } PCH_SMM_PROTOCOL;
549 
550 ///
551 /// Define a structure to help us identify the generic protocol
552 ///
553 #define PROTOCOL_SIGNATURE  SIGNATURE_32 ('P', 'R', 'O', 'T')
554 
555 typedef struct {
556   UINTN                 Signature;
557 
558   PCH_SMM_PROTOCOL_TYPE Type;
559   EFI_GUID              *Guid;
560   PCH_SMM_PROTOCOL      Protocols;
561 } PCH_SMM_QUALIFIED_PROTOCOL;
562 
563 #define QUALIFIED_PROTOCOL_FROM_GENERIC(_generic) \
564   CR ( \
565   _generic, \
566   PCH_SMM_QUALIFIED_PROTOCOL, \
567   Protocols, \
568   PROTOCOL_SIGNATURE \
569   )
570 
571 ///
572 /// Create private data for the protocols that we'll publish
573 ///
574 typedef struct {
575   LIST_ENTRY                  CallbackDataBase;
576   EFI_HANDLE                  SmiHandle;
577   EFI_HANDLE                  InstallMultProtHandle;
578   PCH_SMM_QUALIFIED_PROTOCOL  Protocols[PCH_SMM_PROTOCOL_TYPE_MAX];
579 } PRIVATE_DATA;
580 
581 extern PRIVATE_DATA           mPrivateData;
582 extern UINT16                 mAcpiBaseAddr;
583 extern UINT16                 mTcoBaseAddr;
584 /**
585   Get the Software Smi value
586 
587   @param[in] Record               No use
588   @param[out] Context             The context that includes Software Smi value to be filled
589 
590 **/
591 VOID
592 EFIAPI
593 SwGetContext (
594   IN  DATABASE_RECORD    *Record,
595   OUT PCH_SMM_CONTEXT    *Context
596   );
597 
598 /**
599   Check whether software SMI value of two contexts match
600 
601   @param[in] Context1             Context 1 that includes software SMI value 1
602   @param[in] Context2             Context 2 that includes software SMI value 2
603 
604   @retval FALSE                   Software SMI value match
605   @retval TRUE                    Software SMI value don't match
606 **/
607 BOOLEAN
608 EFIAPI
609 SwCmpContext (
610   IN PCH_SMM_CONTEXT     *Context1,
611   IN PCH_SMM_CONTEXT     *Context2
612   );
613 
614 /**
615   Gather the CommBuffer information of SmmSwDispatch2.
616 
617   @param[in]  Record              No use
618   @param[out] CommBuffer          Point to the CommBuffer structure
619   @param[out] CommBufferSize      Point to the Size of CommBuffer structure
620 
621 **/
622 VOID
623 EFIAPI
624 SwGetCommBuffer (
625   IN  DATABASE_RECORD    *Record,
626   OUT VOID               **CommBuffer,
627   OUT UINTN              *CommBufferSize
628   );
629 
630 /**
631   Get the Sleep type
632 
633   @param[in] Record               No use
634   @param[out] Context             The context that includes SLP_TYP bits to be filled
635 
636 **/
637 VOID
638 EFIAPI
639 SxGetContext (
640   IN  DATABASE_RECORD    *Record,
641   OUT PCH_SMM_CONTEXT    *Context
642   );
643 
644 /**
645   Init required protocol for Pch Sw Dispatch protocol.
646 
647 
648 **/
649 VOID
650 PchSwDispatchInit (
651   VOID
652   );
653 
654 /**
655   Check whether sleep type of two contexts match
656 
657   @param[in] Context1             Context 1 that includes sleep type 1
658   @param[in] Context2             Context 2 that includes sleep type 2
659 
660   @retval FALSE                   Sleep types match
661   @retval TRUE                    Sleep types don't match
662 **/
663 BOOLEAN
664 EFIAPI
665 SxCmpContext (
666   IN PCH_SMM_CONTEXT     *Context1,
667   IN PCH_SMM_CONTEXT     *Context2
668   );
669 
670 /**
671   Update the elapsed time from the Interval data of DATABASE_RECORD
672 
673   @param[in] Record               The pointer to the DATABASE_RECORD.
674   @param[out] HwContext           The Context to be updated.
675 
676 **/
677 VOID
678 EFIAPI
679 PeriodicTimerGetContext (
680   IN  DATABASE_RECORD    *Record,
681   OUT PCH_SMM_CONTEXT    *Context
682   );
683 
684 /**
685   Check whether Periodic Timer of two contexts match
686 
687   @param[in] Context1             Context 1 that includes Periodic Timer  1
688   @param[in] Context2             Context 2 that includes Periodic Timer  2
689 
690   @retval FALSE                   Periodic Timer match
691   @retval TRUE                    Periodic Timer don't match
692 **/
693 BOOLEAN
694 EFIAPI
695 PeriodicTimerCmpContext (
696   IN PCH_SMM_CONTEXT     *Context1,
697   IN PCH_SMM_CONTEXT     *Context2
698   );
699 
700 /**
701   Gather the CommBuffer information of SmmPeriodicTimerDispatch2.
702 
703   @param[in]  Record              No use
704   @param[out] CommBuffer          Point to the CommBuffer structure
705   @param[out] CommBufferSize      Point to the Size of CommBuffer structure
706 
707 **/
708 VOID
709 EFIAPI
710 PeriodicTimerGetCommBuffer (
711   IN  DATABASE_RECORD    *Record,
712   OUT VOID               **CommBuffer,
713   OUT UINTN              *CommBufferSize
714   );
715 
716 /**
717   Get the power button status.
718 
719   @param[in] Record               The pointer to the DATABASE_RECORD.
720   @param[out] Context             Calling context from the hardware, will be updated with the current power button status.
721 
722 **/
723 VOID
724 EFIAPI
725 PowerButtonGetContext (
726   IN  DATABASE_RECORD    *Record,
727   OUT PCH_SMM_CONTEXT    *Context
728   );
729 
730 /**
731   Check whether Power Button status of two contexts match
732 
733   @param[in] Context1             Context 1 that includes Power Button status 1
734   @param[in] Context2             Context 2 that includes Power Button status 2
735 
736   @retval FALSE                   Power Button status match
737   @retval TRUE                    Power Button status don't match
738 **/
739 BOOLEAN
740 EFIAPI
741 PowerButtonCmpContext (
742   IN PCH_SMM_CONTEXT     *Context1,
743   IN PCH_SMM_CONTEXT     *Context2
744   );
745 
746 /**
747   This function is responsible for calculating and enabling any timers that are required
748   to dispatch messages to children. The SrcDesc argument isn't acutally used.
749 
750   @param[in] SrcDesc              Pointer to the PCH_SMM_SOURCE_DESC instance.
751 
752 **/
753 VOID
754 EFIAPI
755 PchSmmPeriodicTimerClearSource (
756   IN PCH_SMM_SOURCE_DESC *SrcDesc
757   );
758 
759 /**
760   This services returns the next SMI tick period that is supported by the chipset.
761   The order returned is from longest to shortest interval period.
762 
763   @param[in] This                 Pointer to the EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL instance.
764   @param[in, out] SmiTickInterval Pointer to pointer of the next shorter SMI interval period that is supported by the child.
765 
766   @retval EFI_SUCCESS             The service returned successfully.
767   @retval EFI_INVALID_PARAMETER   The parameter SmiTickInterval is invalid.
768 **/
769 EFI_STATUS
770 PchSmmPeriodicTimerDispatchGetNextShorterInterval (
771   IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL    *This,
772   IN OUT UINT64                                         **SmiTickInterval
773   );
774 
775 /**
776   Install PCH SMM periodic timer control protocol
777 
778   @param[in] Handle                     handle for this driver
779 
780   @retval EFI_SUCCESS                   Driver initialization completed successfully
781 **/
782 EFI_STATUS
783 EFIAPI
784 InstallPchSmmPeriodicTimerControlProtocol (
785   IN EFI_HANDLE                         Handle
786   );
787 
788 /**
789   When we get an SMI that indicates that we are transitioning to a sleep state,
790   we need to actually transition to that state.  We do this by disabling the
791   "SMI on sleep enable" feature, which generates an SMI when the operating system
792   tries to put the system to sleep, and then physically putting the system to sleep.
793 **/
794 VOID
795 PchSmmSxGoToSleep (
796   VOID
797   );
798 
799 /**
800   Check and clear NEWCENTURY_STS.
801   It will clear the SMI status once it happens.
802 
803   @param[in] SrcDesc                    Pointer to the PCH SMI source description table
804 **/
805 VOID
806 EFIAPI
807 PchTcoClearNewCenturySts (
808   PCH_SMM_SOURCE_DESC                   *SrcDesc
809   );
810 
811 /**
812   Install protocols of PCH specifics SMI types, including
813   PCH TCO SMI types, PCH PCIE SMI types, PCH ACPI SMI types, PCH MISC SMI types.
814 
815   @retval                               the result of protocol installation
816 **/
817 EFI_STATUS
818 InstallPchSmiDispatchProtocols (
819   VOID
820   );
821 
822 /**
823   The function to dispatch all callback function of PCH SMI types.
824 
825   @retval EFI_SUCCESS                   Function successfully completed
826   @retval EFI_UNSUPPORTED               no
827 **/
828 EFI_STATUS
829 PchSmiTypeCallbackDispatcher (
830   IN  DATABASE_RECORD                   *Record
831   );
832 
833 /**
834   The register function used to register SMI handler of IoTrap event.
835   This is internal function and only used by Iotrap module.
836 
837   @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
838   @param[in]  IoTrapIndex               Index number of IOTRAP register
839   @param[out] DispatchHandle            Handle of dispatch function to register.
840 
841   @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
842   @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
843   @retval EFI_SUCCESS                   The database record is created successfully.
844 **/
845 EFI_STATUS
846 PchInternalIoTrapSmiRegister (
847   IN  PCH_SMI_DISPATCH_CALLBACK         DispatchFunction,
848   IN  UINTN                             IoTrapIndex,
849   OUT EFI_HANDLE                        *DispatchHandle
850   );
851 
852 /**
853   Unregister a child SMI source dispatch function with a parent SMM driver
854 
855   @param[in] DispatchHandle             Handle of dispatch function to deregister.
856 
857   @retval EFI_SUCCESS                   The dispatch function has been successfully
858                                         unregistered and the SMI source has been disabled
859                                         if there are no other registered child dispatch
860                                         functions for this SMI source.
861   @retval EFI_INVALID_PARAMETER         Handle is invalid.
862 **/
863 EFI_STATUS
864 PchInternalIoTrapSmiUnRegister (
865   IN  EFI_HANDLE                        DispatchHandle
866   );
867 
868 /**
869   Register an eSPI SMI handler based on the type
870 
871   @param[in]  DispatchFunction        Callback in an event of eSPI SMI
872   @param[in]  PchSmiTypes             The eSPI type published by PchSmiDispatch
873   @param[out] DispatchHandle          The callback handle
874 
875   @retval     EFI_INVALID_PARAMETER   Error with NULL SMI source description
876   @retval     EFI_OUT_OF_RESOURCES    Fail to allocate pool for database record
877   @retval     EFI_SUCCESS             Registration is successful.
878 **/
879 EFI_STATUS
880 PchInternalEspiSmiRegister (
881   IN  PCH_SMI_DISPATCH_CALLBACK         DispatchFunction,
882   IN  PCH_SMI_TYPES                     PchSmiTypes,
883   OUT EFI_HANDLE                        *DispatchHandle
884   );
885 
886 /**
887   Unregister an eSPI SMI handler
888 
889   @param[in] DispatchHandle             Handle of dispatch function to deregister.
890 
891   @retval EFI_SUCCESS                   The dispatch function has been successfully
892                                         unregistered and the SMI source has been disabled
893                                         if there are no other registered child dispatch
894                                         functions for this SMI source.
895   @retval EFI_INVALID_PARAMETER         Handle is invalid.
896 **/
897 EFI_STATUS
898 PchInternalEspiSmiUnRegister (
899   IN  EFI_HANDLE                        DispatchHandle
900   );
901 
902 /**
903   The internal function used to create and insert a database record
904   for SMI record of Pch Smi types.
905 
906   @param[in]  SrcDesc                   The pointer to the SMI source description
907   @param[in]  DispatchFunction          Pointer to dispatch function to be invoked for this SMI source
908   @param[in]  PchSmiType                Specific SMI type of PCH SMI
909   @param[out] DispatchHandle            Handle of dispatch function to register.
910 
911   @retval EFI_INVALID_PARAMETER         Error with NULL SMI source description
912   @retval EFI_OUT_OF_RESOURCES          Fail to allocate pool for database record
913   @retval EFI_SUCCESS                   The database record is created successfully.
914 **/
915 EFI_STATUS
916 PchSmiRecordInsert (
917   IN  EFI_GUID                          *ProtocolGuid,
918   IN  PCH_SMM_SOURCE_DESC               *SrcDesc,
919   IN  PCH_SMI_CALLBACK_FUNCTIONS        DispatchFunction,
920   IN  PCH_SMI_TYPES                     PchSmiType,
921   OUT EFI_HANDLE                        *DispatchHandle
922   );
923 
924 extern PCH_SMM_SOURCE_DESC mSrcDescSerialIrq;
925 
926 /**
927   Clear the TCO SMI status bit after the SMI handling is done
928 
929   @param[in] SrcDesc                    Pointer to the PCH SMI source description table
930 
931 **/
932 VOID
933 EFIAPI
934 PchTcoSmiClearSource (
935   PCH_SMM_SOURCE_DESC                   *SrcDesc
936   );
937 
938 /**
939   Initialize Source descriptor structure
940 
941   @param[in] SrcDesc                    Pointer to the PCH SMI source description table
942 
943 **/
944 VOID
945 NullInitSourceDesc (
946   PCH_SMM_SOURCE_DESC                   *SrcDesc
947   );
948 
949 #endif
950