1 /** @file
2   Main implementation source file for the Io Trap SMM driver
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 <Protocol/PchNvsArea.h>
9 #include <Library/SmiHandlerProfileLib.h>
10 #include <Register/PchPcrRegs.h>
11 #include <Register/PchRegsPsth.h>
12 #include <Register/PchDmiRegs.h>
13 
14 #define GENERIC_IOTRAP_SIZE 0x100
15 
16 //
17 // Module global variables
18 //
19 GLOBAL_REMOVE_IF_UNREFERENCED EFI_HANDLE                      mDriverImageHandle;
20 GLOBAL_REMOVE_IF_UNREFERENCED EFI_HANDLE                      mIoTrapHandle;
21 
22 GLOBAL_REMOVE_IF_UNREFERENCED IO_TRAP_INSTANCE                mIoTrapData;
23 GLOBAL_REMOVE_IF_UNREFERENCED IO_TRAP_RECORD                  *mIoTrapRecord;
24 GLOBAL_REMOVE_IF_UNREFERENCED PCH_NVS_AREA                    *mPchNvsArea;
25 
26 
27 static CONST UINT16             mLengthTable[10] = { 1, 2, 3, 4, 8, 16, 32, 64, 128, 256 };
28 
29 /**
30   Helper function that encapsulates IoTrap register access.
31   IO trap related register updates must be made in 2 registers, IOTRAP and DMI source decode.
32 
33   @param[in] TrapHandlerNum    trap number (0-3)
34   @param[in] Value             value to be written in both registers
35   @param[in] SaveToBootscript  if true, this register write will be saved to bootscript
36 
37 **/
38 VOID
SetIoTrapLowDword(IN UINT8 TrapHandlerNum,IN UINT32 Value,IN BOOLEAN SaveToBootscript)39 SetIoTrapLowDword (
40   IN UINT8   TrapHandlerNum,
41   IN UINT32  Value,
42   IN BOOLEAN SaveToBootscript
43   )
44 {
45   UINT32  BitMask;
46   UINT32  BitValue;
47   //
48   // To provide sequentially consistent programming model for IO trap
49   // all pending IO cycles must be flushed before enabling and before disabling a trap.
50   // Without this the trap may trigger due to IO cycle issued before the trap is enabled or a cycle issued before the trap is disabled might be missed.
51   // a. Issues a MemRd to PSTH IO Trap Enable bit -> This serves to flush all previous IO cycles.
52   // b. Then only issues a MemWr to PSTH IO Trap Enable == Value
53   // c. Issues another MemRd to PSTH IO Trap Enable bit -> This serves to push the MemWr to PSTH and confirmed that IO Trap is in fact enabled
54   //
55   PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8);
56   PchPcrWrite32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8, Value);
57   PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8);
58 
59   PchPcrWrite32 (PID_DMI, R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8, Value);
60   //
61   // Read back DMI IOTRAP register to enforce ordering so DMI write is completed before any IO reads
62   // from other threads which may occur after this point (after SMI exit).
63   //
64   PchPcrRead32 (PID_DMI, R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8);
65   if (SaveToBootscript) {
66     //
67     // Ignore the value check of PCH_PCR_BOOT_SCRIPT_READ
68     //
69     BitMask  = 0;
70     BitValue = 0;
71 
72     PCH_PCR_BOOT_SCRIPT_READ (S3BootScriptWidthUint32, PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8, &BitMask, &BitValue);
73     PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8, 1, &Value);
74     PCH_PCR_BOOT_SCRIPT_READ (S3BootScriptWidthUint32, PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8, &BitMask, &BitValue);
75     PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_DMI, R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8, 1, &Value);
76   }
77 }
78 
79 /**
80   Helper function that encapsulates IoTrap register access.
81   IO trap related register updates must be made in 2 registers, IOTRAP and DMI source decode.
82 
83   @param[in] TrapHandlerNum    trap number (0-3)
84   @param[in] Value             value to be written in both registers
85   @param[in] SaveToBootscript  if true, this register write will be saved to bootscript
86 
87 **/
88 VOID
SetIoTrapHighDword(IN UINT8 TrapHandlerNum,IN UINT32 Value,IN BOOLEAN SaveToBootscript)89 SetIoTrapHighDword (
90   IN UINT8   TrapHandlerNum,
91   IN UINT32  Value,
92   IN BOOLEAN SaveToBootscript
93   )
94 {
95   PchPcrWrite32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8 + 4, Value);
96   PchPcrWrite32 (PID_DMI, R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8 + 4, Value);
97   if (SaveToBootscript) {
98     PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8 + 4, 1, &Value);
99     PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_DMI, R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8 + 4, 1, &Value);
100   }
101 }
102 
103 /**
104   Clear pending IOTRAP status.
105   If IOTRAP status is pending and IOTRAP is disabled, then BIOS will not find a match SMI source
106   and will not dispatch any SMI handler for it. The pending status will lead to SMI storm.
107   This prevents that IOTRAP gets triggered by pending IO cycles even after it's disabled.
108 
109   @param[in] TrapHandlerNum    trap number (0-3)
110 
111 **/
112 VOID
ClearPendingIoTrapStatus(IN UINT8 TrapHandlerNum)113 ClearPendingIoTrapStatus (
114   IN UINT8   TrapHandlerNum
115   )
116 {
117   PchPcrWrite32 (PID_PSTH, R_PSTH_PCR_TRPST, (UINT32)(1 << TrapHandlerNum));
118 }
119 
120 /**
121   IO resources allocated to IO traps need to be reported to OS so that they don't get reused.
122   This function makes IO trap allocation data available to ACPI
123 
124   @param[in] TrapHandlerNum  trap number (0-3)
125   @param[in] BaseAddress     address of allocated IO resource
126   @param[in] Track           TRUE = resource allocated, FALSE = resource freed
127 
128 **/
129 VOID
UpdateIoTrapAcpiResources(IN UINT8 TrapHandlerNum,IN EFI_PHYSICAL_ADDRESS BaseAddress,IN BOOLEAN Track)130 UpdateIoTrapAcpiResources (
131   IN UINT8                TrapHandlerNum,
132   IN EFI_PHYSICAL_ADDRESS BaseAddress,
133   IN BOOLEAN              Track
134   )
135 {
136 
137   if (Track == TRUE) {
138     mPchNvsArea->IoTrapAddress[TrapHandlerNum] = (UINT16) BaseAddress;
139     mPchNvsArea->IoTrapStatus[TrapHandlerNum] = 1;
140   } else {
141     mPchNvsArea->IoTrapStatus[TrapHandlerNum] = 0;
142   }
143 }
144 
145 /**
146   Get address from IOTRAP low dword.
147 
148   @param[in] IoTrapRegLowDword    IOTRAP register low dword
149 
150   @retval                         Address of IOTRAP setting.
151 **/
152 STATIC
153 UINT16
AddressFromLowDword(UINT32 IoTrapRegLowDword)154 AddressFromLowDword (
155   UINT32  IoTrapRegLowDword
156   )
157 {
158   return (UINT16) (IoTrapRegLowDword & B_PSTH_PCR_TRPREG_AD);
159 }
160 
161 /**
162   Get length from IOTRAP low dword.
163 
164   @param[in] IoTrapRegLowDword    IOTRAP register low dword
165 
166   @retval                         Length of IOTRAP setting.
167 **/
168 STATIC
169 UINT16
LengthFromLowDword(UINT32 IoTrapRegLowDword)170 LengthFromLowDword (
171   UINT32  IoTrapRegLowDword
172   )
173 {
174   return (UINT16) (((IoTrapRegLowDword >> 16) & 0xFC) + 4);
175 }
176 
177 /**
178   Get ByteEnable from IOTRAP high dword.
179 
180   @param[in] IoTrapRegHighDword   IOTRAP register high dword
181 
182   @retval                         ByteEnable of IOTRAP setting.
183 **/
184 STATIC
185 UINT8
ByteEnableFromHighDword(UINT32 IoTrapRegHighDword)186 ByteEnableFromHighDword (
187   UINT32  IoTrapRegHighDword
188   )
189 {
190   return (UINT8) (IoTrapRegHighDword & 0x0F);
191 }
192 
193 /**
194   Get ByteEnableMask from IOTRAP high dword.
195 
196   @param[in] IoTrapRegHighDword   IOTRAP register high dword
197 
198   @retval                         ByteEnableMask of IOTRAP setting.
199 **/
200 STATIC
201 UINT8
ByteEnableMaskFromHighDword(UINT32 IoTrapRegHighDword)202 ByteEnableMaskFromHighDword (
203   UINT32  IoTrapRegHighDword
204   )
205 {
206   return (UINT8) ((IoTrapRegHighDword & 0xF0) >> 4);
207 }
208 
209 /**
210   Check the IoTrap register matches the IOTRAP EX content.
211 
212   @param[in] IoTrapRecord         IOTRAP registration record structure
213   @param[in] IoTrapRegLowDword    IOTRAP register low dword
214   @param[in] IoTrapRegHighDword   IOTRAP register high dword
215 
216   @retval    TRUE                 Content matched
217              FALSE                Content mismatched
218 **/
219 STATIC
220 BOOLEAN
IsIoTrapExContentMatched(IO_TRAP_RECORD * IoTrapRecord,UINT32 IoTrapRegLowDword,UINT32 IoTrapRegHighDword)221 IsIoTrapExContentMatched (
222   IO_TRAP_RECORD  *IoTrapRecord,
223   UINT32          IoTrapRegLowDword,
224   UINT32          IoTrapRegHighDword
225   )
226 {
227   if ((IoTrapRecord->Context.Address == AddressFromLowDword (IoTrapRegLowDword))          &&
228       (IoTrapRecord->Context.Length == LengthFromLowDword (IoTrapRegLowDword))            &&
229       (IoTrapRecord->Context.ByteEnable == ByteEnableFromHighDword (IoTrapRegHighDword))  &&
230       (IoTrapRecord->Context.ByteEnableMask == ByteEnableMaskFromHighDword (IoTrapRegHighDword)))
231   {
232     return TRUE;
233   }
234   return FALSE;
235 }
236 
237 
238 /**
239   The helper function for IoTrap callback dispacther
240 
241   @param[in] TrapHandlerNum  trap number (0-3)
242 **/
243 VOID
IoTrapDispatcherHelper(UINTN TrapHandlerNum)244 IoTrapDispatcherHelper (
245   UINTN                                     TrapHandlerNum
246   )
247 {
248   IO_TRAP_RECORD                            *RecordInDb;
249   LIST_ENTRY                                *LinkInDb;
250   EFI_SMM_IO_TRAP_REGISTER_CONTEXT          CurrentIoTrapRegisterData;
251   EFI_SMM_IO_TRAP_CONTEXT                   CurrentIoTrapContextData;
252   UINT16                                    BaseAddress;
253   UINT16                                    StartAddress;
254   UINT16                                    EndAddress;
255   UINT32                                    Data32;
256   UINT8                                     ActiveHighByteEnable;
257   BOOLEAN                                   ReadCycle;
258   UINT32                                    WriteData;
259 
260   if (!IsListEmpty (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase))) {
261     Data32 = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPC);
262     WriteData = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPD);
263 
264     BaseAddress           = (UINT16) (Data32 & B_PSTH_PCR_TRPC_IOA);
265     ActiveHighByteEnable  = (UINT8)((Data32 & B_PSTH_PCR_TRPC_AHBE) >> 16);
266     ReadCycle             = (BOOLEAN) ((Data32 & B_PSTH_PCR_TRPC_RW) == B_PSTH_PCR_TRPC_RW);
267     //
268     // StartAddress and EndAddress will be equal if it's byte access
269     //
270     EndAddress    = (UINT16) (HighBitSet32 ((UINT32) (ActiveHighByteEnable))) + BaseAddress;
271     StartAddress  = (UINT16) (LowBitSet32 ((UINT32) (ActiveHighByteEnable))) + BaseAddress;
272 
273     CurrentIoTrapRegisterData.Type = (EFI_SMM_IO_TRAP_DISPATCH_TYPE)ReadCycle;
274     CurrentIoTrapContextData.WriteData = WriteData;
275 
276     LinkInDb = GetFirstNode (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase));
277 
278     while (!IsNull (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase), LinkInDb)) {
279       RecordInDb = IO_TRAP_RECORD_FROM_LINK (LinkInDb);
280 
281       //
282       // If MergeDisable is TRUE, no need to check the address range, dispatch the callback function directly.
283       //
284       if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable) {
285         if (RecordInDb->IoTrapCallback != NULL) {
286           RecordInDb->IoTrapCallback (&RecordInDb->Link, &CurrentIoTrapContextData, NULL, NULL);
287         }
288         if (RecordInDb->IoTrapExCallback != NULL) {
289           RecordInDb->IoTrapExCallback (BaseAddress, ActiveHighByteEnable, !ReadCycle, WriteData);
290         }
291         //
292         // Expect only one callback available. So break immediately.
293         //
294         break;
295       //
296       // If MergeDisable is FALSE, check the address range and trap type.
297       //
298       } else {
299         if ((RecordInDb->Context.Address <= StartAddress) &&
300             (RecordInDb->Context.Address + RecordInDb->Context.Length > EndAddress)) {
301           if ((RecordInDb->Context.Type == IoTrapExTypeReadWrite) || (RecordInDb->Context.Type == (IO_TRAP_EX_DISPATCH_TYPE) CurrentIoTrapRegisterData.Type)) {
302             //
303             // Pass the IO trap context information
304             //
305             RecordInDb->IoTrapCallback (&RecordInDb->Link, &CurrentIoTrapContextData, NULL, NULL);
306           }
307           //
308           // Break if the address is match
309           //
310           break;
311         } else {
312           LinkInDb = GetNextNode (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase), &RecordInDb->Link);
313           if (IsNull (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase), LinkInDb)) {
314             //
315             // An IO access was trapped that does not have a handler registered.
316             // This indicates an error condition.
317             //
318             ASSERT (FALSE);
319           }
320         }
321       } // end of if else block
322     } // end of while loop
323   } // end of if else block
324 }
325 
326 /**
327   IoTrap dispatcher for IoTrap register 0.
328 
329   @param[in] DispatchHandle             Handle of dispatch function
330 **/
331 VOID
332 EFIAPI
IoTrapDispatcher0(IN EFI_HANDLE DispatchHandle)333 IoTrapDispatcher0 (
334   IN  EFI_HANDLE                        DispatchHandle
335   )
336 {
337   IoTrapDispatcherHelper (0);
338 }
339 
340 /**
341   IoTrap dispatcher for IoTrap register 1.
342 
343   @param[in] DispatchHandle             Handle of dispatch function
344 **/
345 VOID
346 EFIAPI
IoTrapDispatcher1(IN EFI_HANDLE DispatchHandle)347 IoTrapDispatcher1 (
348   IN  EFI_HANDLE                        DispatchHandle
349   )
350 {
351   IoTrapDispatcherHelper (1);
352 }
353 
354 /**
355   IoTrap dispatcher for IoTrap register 2.
356 
357   @param[in] DispatchHandle             Handle of dispatch function
358 **/
359 VOID
360 EFIAPI
IoTrapDispatcher2(IN EFI_HANDLE DispatchHandle)361 IoTrapDispatcher2 (
362   IN  EFI_HANDLE                        DispatchHandle
363   )
364 {
365   IoTrapDispatcherHelper (2);
366 }
367 
368 /**
369   IoTrap dispatcher for IoTrap register 3.
370 
371   @param[in] DispatchHandle             Handle of dispatch function
372 **/
373 VOID
374 EFIAPI
IoTrapDispatcher3(IN EFI_HANDLE DispatchHandle)375 IoTrapDispatcher3 (
376   IN  EFI_HANDLE                        DispatchHandle
377   )
378 {
379   IoTrapDispatcherHelper (3);
380 }
381 
382 /**
383   IoTrap registratrion helper fucntion.
384 
385   @param[in] DispatchHandle             Handle of dispatch function
386   @param[in] IoTrapDispatchFunction     Dispatch function of IoTrapDispatch2Protocol.
387                                         This could be NULL if it's not from IoTrapDispatch2Protocol.
388   @param[in] IoTrapExDispatchFunction   Dispatch function of IoTrapExDispatchProtocol.
389                                         This could be NULL if it's not from IoTrapExDispatchProtocol.
390   @param[in out] Address                The pointer of IO Address.
391                                         If the input Addres is 0, it will return the address assigned
392                                         by registration to this caller.
393   @param[in] Length                     Length of IO address range.
394   @param[in] Type                       Read/Write type of IO trap.
395   @param[in] ByteEnable                 Bitmap to enable trap for each byte of every dword alignment address.
396   @param[in] ByteEnableMask             ByteEnableMask bitwise to ignore the ByteEnable setting.
397 
398   @retval    EFI_INVALID_PARAMETER      If Type is invalid,
399                                         If Length is invalid,
400                                         If Address is invalid,
401              EFI_ACCESS_DENIED          If the SmmReadyToLock event has been triggered,
402              EFI_OUT_OF_RESOURCES       If run out of IoTrap register resource,
403                                         If run out of SMM memory pool,
404              EFI_SUCCESS                IoTrap register successfully.
405 **/
406 EFI_STATUS
IoTrapRegisterHelper(OUT EFI_HANDLE * DispatchHandle,IN EFI_SMM_HANDLER_ENTRY_POINT2 IoTrapDispatchFunction,IN IO_TRAP_EX_DISPATCH_CALLBACK IoTrapExDispatchFunction,IN OUT UINT16 * Address,IN UINT16 Length,IN IO_TRAP_EX_DISPATCH_TYPE Type,IN UINT8 ByteEnable,IN UINT8 ByteEnableMask)407 IoTrapRegisterHelper (
408   OUT       EFI_HANDLE                             *DispatchHandle,
409   IN        EFI_SMM_HANDLER_ENTRY_POINT2           IoTrapDispatchFunction,
410   IN        IO_TRAP_EX_DISPATCH_CALLBACK           IoTrapExDispatchFunction,
411   IN OUT    UINT16                                 *Address,
412   IN        UINT16                                 Length,
413   IN        IO_TRAP_EX_DISPATCH_TYPE               Type,
414   IN        UINT8                                  ByteEnable,
415   IN        UINT8                                  ByteEnableMask
416   )
417 {
418   EFI_STATUS            Status;
419   EFI_PHYSICAL_ADDRESS  BaseAddress;
420   UINT32                UsedLength;
421   UINT8                 TrapHandlerNum;
422   UINT32                IoTrapRegLowDword;
423   UINT32                IoTrapRegHighDword;
424   BOOLEAN               TempMergeDisable;
425 
426   DEBUG ((DEBUG_INFO, "IoTrapRegisterHelper\n"));
427   DEBUG ((DEBUG_INFO, "Address:%x \n", *Address));
428   DEBUG ((DEBUG_INFO, "Length:%x \n", Length));
429   DEBUG ((DEBUG_INFO, "Type:%x \n", Type));
430   DEBUG ((DEBUG_INFO, "ByteEnable:%x \n", ByteEnable));
431   DEBUG ((DEBUG_INFO, "ByteEnableMask:%x \n", ByteEnableMask));
432 
433   //
434   // Return error if the type is invalid
435   //
436   if (Type >= IoTrapExTypeMaximum) {
437     DEBUG ((DEBUG_ERROR, "The Dispatch Type %0X is invalid! \n", Type));
438     return EFI_INVALID_PARAMETER;
439   }
440   //
441   // Return error if the Length is invalid
442   //
443   if (Length < 1 || Length > GENERIC_IOTRAP_SIZE) {
444     DEBUG ((DEBUG_ERROR, "The Dispatch Length %0X is invalid! \n", Length));
445     return EFI_INVALID_PARAMETER;
446   }
447   //
448   // Return error if the address is invalid
449   // PCH supports non-aligned address but (Address % 4 + Length) must not be more than 4
450   //
451   if (((Length & (Length - 1)) != 0) && (Length != 3)) {
452     DEBUG ((DEBUG_ERROR, "The Dispatch Length is not power of 2 \n"));
453     return EFI_INVALID_PARAMETER;
454   }
455 
456   if (((Length >= 4) && (*Address & 0x3)) ||
457       ((Length < 4) && (((*Address & 0x3) + Length) > 4))) {
458     DEBUG ((DEBUG_ERROR, "PCH does not support Dispatch Address %0X and Length %0X combination \n", *Address, Length));
459     return EFI_INVALID_PARAMETER;
460   }
461 
462   if ((Length >= 4) && ((*Address & (Length - 1)) != 0)) {
463     DEBUG ((DEBUG_ERROR, "Dispatch Address %0X is not aligned to the Length %0X \n", *Address, Length));
464     return EFI_INVALID_PARAMETER;
465   }
466 
467   //
468   // Return access denied if the SmmReadyToLock event has been triggered
469   //
470   if (mReadyToLock == TRUE) {
471     DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock event has been triggered! \n"));
472     return EFI_ACCESS_DENIED;
473   }
474 
475   if (*Address) {
476     TempMergeDisable = TRUE;
477   }else {
478     TempMergeDisable = FALSE;
479   }
480   //
481   // Loop through the first IO Trap handler, looking for the suitable handler
482   //
483   for (TrapHandlerNum = 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; TrapHandlerNum++) {
484     //
485     // Get information from Io Trap handler register
486     //
487     IoTrapRegLowDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8);
488 
489     //
490     // Check if the IO Trap handler is not used
491     //
492     if (AddressFromLowDword (IoTrapRegLowDword) == 0) {
493       //
494       //  Search available IO address and allocate it if the IO address is 0
495       //
496       BaseAddress = *Address;
497       if (BaseAddress == 0) {
498         //
499         // Allocate 256 byte range from GCD for common pool usage
500         //
501         if ((PcdGet8 (PcdEfiGcdAllocateType) == EfiGcdAllocateMaxAddressSearchBottomUp) || (PcdGet8 (PcdEfiGcdAllocateType) == EfiGcdAllocateMaxAddressSearchTopDown)) {
502           BaseAddress = 0xFFFF;
503         }
504         Status = gDS->AllocateIoSpace (
505                         PcdGet8 (PcdEfiGcdAllocateType),
506                         EfiGcdIoTypeIo,
507                         8,
508                         GENERIC_IOTRAP_SIZE,
509                         &BaseAddress,
510                         mDriverImageHandle,
511                         NULL
512                         );
513         if (EFI_ERROR (Status)) {
514           DEBUG ((DEBUG_ERROR, "Can't find any available IO address! \n"));
515           return EFI_OUT_OF_RESOURCES;
516         }
517 
518         *Address   = (UINT16) BaseAddress;
519         UsedLength = GENERIC_IOTRAP_SIZE;
520         mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength = Length;
521         mIoTrapData.Entry[TrapHandlerNum].ReservedAcpiIoResource = TRUE;
522         UpdateIoTrapAcpiResources (TrapHandlerNum, BaseAddress, TRUE);
523       } else {
524         BaseAddress &= B_PSTH_PCR_TRPREG_AD;
525         UsedLength = Length;
526       }
527 
528       Status = PchInternalIoTrapSmiRegister (
529                  mIoTrapData.Entry[TrapHandlerNum].CallbackDispatcher,
530                  TrapHandlerNum,
531                  &mIoTrapHandle
532                  );
533 
534       ASSERT_EFI_ERROR (Status);
535       mIoTrapData.Entry[TrapHandlerNum].IoTrapHandle = mIoTrapHandle;
536 
537       //
538       // Fill in the Length, address and Enable the IO Trap SMI
539       //
540       IoTrapRegLowDword = (UINT32) (((UsedLength - 1) & ~(BIT1 + BIT0)) << 16) |
541         (UINT16) BaseAddress |
542         B_PSTH_PCR_TRPREG_TSE;
543 
544       if (UsedLength < 4) {
545         //
546         // The 4 bits is the Byte Enable Mask bits to indicate which byte that are trapped.
547         // The input ByteEnable and ByteEnableMask are ignored in this case.
548         //
549         IoTrapRegHighDword  = (((1 << UsedLength) - 1) << ((*Address & 0x3) + (N_PSTH_PCR_TRPREG_BEM - 32))) |
550           (UINT32) (Type << N_PSTH_PCR_TRPREG_RWIO);
551       } else {
552         //
553         // Fill in the ByteEnable, ByteEnableMask, and Type of Io Trap register
554         //
555         IoTrapRegHighDword  = ((ByteEnableMask & 0xF) << (N_PSTH_PCR_TRPREG_BEM - 32)) |
556           ((ByteEnable & 0xF) << (N_PSTH_PCR_TRPREG_BE - 32)) |
557           (UINT32) (Type << N_PSTH_PCR_TRPREG_RWIO);
558       }
559       SetIoTrapHighDword (TrapHandlerNum, IoTrapRegHighDword, TRUE);
560       SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, TRUE);
561       //
562       // Set MergeDisable flag of the registered IoTrap
563       //
564       mIoTrapData.Entry[TrapHandlerNum].MergeDisable = TempMergeDisable;
565     } else {
566       //
567       // Check next handler if MergeDisable is TRUE or the registered IoTrap if MergeDisable is TRUE
568       // If the Io Trap register is used by IoTrapEx protocol, then the MergeDisable will be FALSE.
569       //
570       if ((TempMergeDisable == TRUE) || (mIoTrapData.Entry[TrapHandlerNum].MergeDisable == TRUE)) {
571         continue;
572       }
573       //
574       // The IO Trap handler is used, calculate the Length
575       //
576       UsedLength  = LengthFromLowDword (IoTrapRegLowDword);
577       BaseAddress = AddressFromLowDword (IoTrapRegLowDword);
578       //
579       //  Assign an addfress from common pool if the caller's address is 0
580       //
581       if (*Address == 0) {
582         //
583         //  Check next handler if it's fully used
584         //
585         if (mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength >= GENERIC_IOTRAP_SIZE) {
586           continue;
587         }
588         //
589         // Check next handler if it's not for a common pool
590         //
591         if (UsedLength < GENERIC_IOTRAP_SIZE) {
592           continue;
593         }
594         //
595         // Check next handler if the size is too big
596         //
597         if (Length >= (UINT16) GENERIC_IOTRAP_SIZE - mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength) {
598           continue;
599         }
600         //
601         // For common pool, we don't need to change the BaseAddress and UsedLength
602         //
603         *Address = (UINT16) (BaseAddress + mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength);
604         mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength += Length;
605       }
606       //
607       // Only set RWM bit when we need both read and write cycles.
608       //
609       IoTrapRegHighDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8 + 4);
610       if ((IoTrapRegHighDword & B_PSTH_PCR_TRPREG_RWM) == 0 &&
611           (UINT32) ((IoTrapRegHighDword & B_PSTH_PCR_TRPREG_RWIO) >> N_PSTH_PCR_TRPREG_RWIO) !=
612           (UINT32) Type) {
613         IoTrapRegHighDword = ((IoTrapRegHighDword | B_PSTH_PCR_TRPREG_RWM) & ~B_PSTH_PCR_TRPREG_RWIO);
614         SetIoTrapHighDword (TrapHandlerNum, IoTrapRegHighDword, TRUE);
615       }
616     }
617     break;
618   }
619 
620   if (TrapHandlerNum >= IO_TRAP_HANDLER_NUM) {
621     DEBUG ((DEBUG_ERROR, "All IO Trap handler is used, no available IO Trap handler! \n"));
622     return EFI_OUT_OF_RESOURCES;
623   }
624   //
625   // Create database record and add to database
626   //
627   Status = gSmst->SmmAllocatePool (
628                     EfiRuntimeServicesData,
629                     sizeof (IO_TRAP_RECORD),
630                     (VOID **) &mIoTrapRecord
631                     );
632 
633   if (EFI_ERROR (Status)) {
634     DEBUG ((DEBUG_ERROR, "Failed to allocate memory for mIoTrapRecord! \n"));
635     return EFI_OUT_OF_RESOURCES;
636   }
637   //
638   // Gather information about the registration request
639   //
640   mIoTrapRecord->Signature               = IO_TRAP_RECORD_SIGNATURE;
641   mIoTrapRecord->Context.Address         = *Address;
642   mIoTrapRecord->Context.Length          = Length;
643   mIoTrapRecord->Context.Type            = Type;
644   mIoTrapRecord->Context.ByteEnable      = ByteEnable;
645   mIoTrapRecord->Context.ByteEnableMask  = ByteEnableMask;
646   mIoTrapRecord->IoTrapCallback          = IoTrapDispatchFunction;
647   mIoTrapRecord->IoTrapExCallback        = IoTrapExDispatchFunction;
648   mIoTrapRecord->IoTrapNumber            = TrapHandlerNum;
649 
650   InsertTailList (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase), &mIoTrapRecord->Link);
651 
652   //
653   // Child's handle will be the address linked list link in the record
654   //
655   *DispatchHandle = (EFI_HANDLE) (&mIoTrapRecord->Link);
656 
657   DEBUG ((DEBUG_INFO, "Result Address:%x \n", *Address));
658   DEBUG ((DEBUG_INFO, "Result Length:%x \n", Length));
659 
660   return EFI_SUCCESS;
661 }
662 
663 /**
664   IoTrap unregistratrion helper fucntion.
665 
666   @param[in] DispatchHandle             Handle of dispatch function
667 
668   @retval    EFI_INVALID_PARAMETER      If DispatchHandle is invalid,
669              EFI_ACCESS_DENIED          If the SmmReadyToLock event has been triggered,
670              EFI_SUCCESS                IoTrap unregister successfully.
671 **/
672 EFI_STATUS
IoTrapUnRegisterHelper(IN EFI_HANDLE DispatchHandle)673 IoTrapUnRegisterHelper (
674   IN EFI_HANDLE                                  DispatchHandle
675   )
676 {
677   EFI_STATUS            Status;
678   IO_TRAP_RECORD        *RecordToDelete;
679   UINT32                IoTrapRegLowDword;
680   EFI_PHYSICAL_ADDRESS  BaseAddress;
681   UINT32                UsedLength;
682   UINT8                 TrapHandlerNum;
683   UINT8                 LengthIndex;
684   BOOLEAN               RequireToDisableIoTrapHandler;
685 
686   if (DispatchHandle == 0) {
687     return EFI_INVALID_PARAMETER;
688   }
689 
690   //
691   // Return access denied if the SmmReadyToLock event has been triggered
692   //
693   if (mReadyToLock == TRUE) {
694     DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the SmmReadyToLock event has been triggered! \n"));
695     return EFI_ACCESS_DENIED;
696   }
697 
698   RecordToDelete = IO_TRAP_RECORD_FROM_LINK (DispatchHandle);
699   //
700   // Take the entry out of the linked list
701   //
702   if (RecordToDelete->Link.ForwardLink == (LIST_ENTRY *) EFI_BAD_POINTER) {
703     return EFI_INVALID_PARAMETER;
704   }
705 
706   RequireToDisableIoTrapHandler = FALSE;
707   //
708   // Loop through the first IO Trap handler, looking for the suitable handler
709   //
710   TrapHandlerNum = RecordToDelete->IoTrapNumber;
711 
712   if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable) {
713     //
714     // Disable the IO Trap handler if it's the only child of the Trap handler
715     //
716     RequireToDisableIoTrapHandler = TRUE;
717   } else {
718     //
719     // Get information from Io Trap handler register
720     //
721     IoTrapRegLowDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8);
722 
723     //
724     // Check next Io Trap handler if the IO Trap handler is not used
725     //
726     if (AddressFromLowDword (IoTrapRegLowDword) != 0) {
727 
728       UsedLength  = LengthFromLowDword (IoTrapRegLowDword);
729       BaseAddress = AddressFromLowDword (IoTrapRegLowDword);
730 
731       //
732       // Check if it's the maximum address of the Io Trap handler
733       //
734       if ((UINTN)(BaseAddress + UsedLength) == (UINTN)(RecordToDelete->Context.Address + RecordToDelete->Context.Length)) {
735 
736         if (BaseAddress == RecordToDelete->Context.Address) {
737           //
738           // Disable the IO Trap handler if it's the only child of the Trap handler
739           //
740           RequireToDisableIoTrapHandler = TRUE;
741         } else {
742           //
743           // Calculate the new IO Trap handler Length
744           //
745           UsedLength = UsedLength - RecordToDelete->Context.Length;
746           //
747           // Check the alignment is dword * power of 2 or not
748           //
749           for (LengthIndex = 0; LengthIndex < sizeof (mLengthTable) / sizeof (UINT16); LengthIndex++) {
750             if (UsedLength == mLengthTable[LengthIndex]) {
751               break;
752             }
753           }
754           //
755           // Do not decrease the length if the alignment is not dword * power of 2
756           //
757           if (LengthIndex < sizeof (mLengthTable) / sizeof (UINT16)) {
758             //
759             // Decrease the length to prevent the IO trap SMI
760             //
761             IoTrapRegLowDword = (UINT32) ((((UsedLength - 1) &~(BIT1 + BIT0)) << 16) | BaseAddress | B_PSTH_PCR_TRPREG_TSE);
762           }
763           SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, TRUE);
764         }
765       }
766     }
767   }
768 
769   if (RequireToDisableIoTrapHandler) {
770     mIoTrapHandle = mIoTrapData.Entry[TrapHandlerNum].IoTrapHandle;
771     Status        = PchInternalIoTrapSmiUnRegister (mIoTrapHandle);
772     ASSERT_EFI_ERROR (Status);
773 
774     SetIoTrapLowDword (TrapHandlerNum, 0, TRUE);
775     SetIoTrapHighDword (TrapHandlerNum, 0, TRUE);
776     //
777     // Also clear pending IOTRAP status.
778     //
779     ClearPendingIoTrapStatus (TrapHandlerNum);
780 
781     mIoTrapData.Entry[TrapHandlerNum].IoTrapHandle = 0;
782     mIoTrapData.Entry[TrapHandlerNum].MergeDisable = FALSE;
783     if (mIoTrapData.Entry[TrapHandlerNum].ReservedAcpiIoResource == TRUE) {
784       mIoTrapData.Entry[TrapHandlerNum].ReservedAcpiIoResource = FALSE;
785       UpdateIoTrapAcpiResources (TrapHandlerNum, 0, FALSE);
786     }
787   }
788 
789   RemoveEntryList (&RecordToDelete->Link);
790   Status = gSmst->SmmFreePool (RecordToDelete);
791   ASSERT_EFI_ERROR (Status);
792 
793   return EFI_SUCCESS;
794 }
795 
796 /**
797   Register a new IO Trap SMI dispatch function with a parent SMM driver.
798   The caller will provide information about the IO trap characteristics via
799   the context.  This includes base address, length, read vs. r/w, etc.
800   This function will autoallocate IO base address from a common pool if the base address is 0,
801   and the RegisterContext Address field will be updated.
802   The service will not perform GCD allocation if the base address is non-zero.
803   In this case, the caller is responsible for the existence and allocation of the
804   specific IO range.
805   This function looks for the suitable handler and Register a new IoTrap handler
806   if the IO Trap handler is not used. It also enable the IO Trap Range to generate
807   SMI.
808 
809   @param[in] This                 Pointer to the EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL instance.
810   @param[in] DispatchFunction     Pointer to dispatch function to be invoked for
811                                   this SMI source.
812   @param[in, out] RegisterContext Pointer to the dispatch function's context.
813                                   The caller fills this context in before calling
814                                   the register function to indicate to the register
815                                   function the IO trap SMI source for which the dispatch
816                                   function should be invoked.  This may not be NULL.
817                                   If the registration address is not 0, it's caller's responsibility
818                                   to reserve the IO resource in ACPI.
819   @param[out] DispatchHandle      Handle of dispatch function, for when interfacing
820                                   with the parent SMM driver, will be the address of linked
821                                   list link in the call back record.  This may not be NULL.
822 
823   @retval EFI_SUCCESS             The dispatch function has been successfully
824                                   registered and the SMI source has been enabled.
825   @retval EFI_DEVICE_ERROR        The driver was unable to enable the SMI source.
826   @retval EFI_OUT_OF_RESOURCES    Insufficient resources are available
827   @retval EFI_INVALID_PARAMETER   Address requested is already in use.
828   @retval EFI_ACCESS_DENIED       Return access denied if the SmmReadyToLock event has been triggered
829 **/
830 EFI_STATUS
831 EFIAPI
IoTrapRegister(IN CONST EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL * This,IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,IN OUT EFI_SMM_IO_TRAP_REGISTER_CONTEXT * RegisterContext,OUT EFI_HANDLE * DispatchHandle)832 IoTrapRegister (
833   IN CONST  EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL     *This,
834   IN        EFI_SMM_HANDLER_ENTRY_POINT2           DispatchFunction,
835   IN OUT    EFI_SMM_IO_TRAP_REGISTER_CONTEXT       *RegisterContext,
836   OUT       EFI_HANDLE                             *DispatchHandle
837   )
838 {
839   EFI_STATUS Status;
840 
841   DEBUG ((DEBUG_INFO, "IoTrapRegister\n"));
842   Status = IoTrapRegisterHelper (
843              DispatchHandle,
844              DispatchFunction,
845              NULL,
846              &(RegisterContext->Address),
847              RegisterContext->Length,
848              (IO_TRAP_EX_DISPATCH_TYPE) RegisterContext->Type,
849              0x00,
850              0x0F);
851 
852   if (!EFI_ERROR (Status)) {
853     SmiHandlerProfileRegisterHandler (
854       &gEfiSmmIoTrapDispatch2ProtocolGuid,
855       DispatchFunction,
856       (UINTN)RETURN_ADDRESS (0),
857       RegisterContext,
858       sizeof (EFI_SMM_IO_TRAP_REGISTER_CONTEXT)
859       );
860   }
861   return Status;
862 }
863 
864 /**
865   Unregister a child SMI source dispatch function with a parent SMM driver.
866 
867   @param[in] This                 Pointer to the EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL instance.
868   @param[in] DispatchHandle       Handle of dispatch function to deregister.
869 
870   @retval EFI_SUCCESS             The dispatch function has been successfully
871                                   unregistered and the SMI source has been disabled
872                                   if there are no other registered child dispatch
873                                   functions for this SMI source.
874   @retval EFI_INVALID_PARAMETER   Handle is invalid.
875   @retval EFI_ACCESS_DENIED       Return access denied if the SmmReadyToLock event has been triggered
876 **/
877 EFI_STATUS
878 EFIAPI
IoTrapUnRegister(IN CONST EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL * This,IN EFI_HANDLE DispatchHandle)879 IoTrapUnRegister (
880   IN CONST EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL    *This,
881   IN EFI_HANDLE                                  DispatchHandle
882   )
883 {
884   IO_TRAP_RECORD *RecordToDelete;
885 
886   RecordToDelete = IO_TRAP_RECORD_FROM_LINK (DispatchHandle);
887   SmiHandlerProfileUnregisterHandler (
888     &gIoTrapExDispatchProtocolGuid,
889     RecordToDelete->IoTrapCallback,
890     &RecordToDelete->Context,
891     sizeof (EFI_SMM_IO_TRAP_REGISTER_CONTEXT)
892     );
893   return IoTrapUnRegisterHelper (DispatchHandle);
894 }
895 
896 /**
897   Register a new IO Trap Ex SMI dispatch function.
898 
899   @param[in] This                 Pointer to the IO_TRAP_EX_DISPATCH_PROTOCOL instance.
900   @param[in] DispatchFunction     Pointer to dispatch function to be invoked for
901                                   this SMI source.
902   @param[in] RegisterContext      Pointer to the dispatch function's context.
903                                   The caller fills this context in before calling
904                                   the register function to indicate to the register
905                                   function the IO trap Ex SMI source for which the dispatch
906                                   function should be invoked.  This MUST not be NULL.
907   @param[out] DispatchHandle      Handle of dispatch function.
908 
909   @retval EFI_SUCCESS             The dispatch function has been successfully
910                                   registered and the SMI source has been enabled.
911   @retval EFI_OUT_OF_RESOURCES    Insufficient resources are available
912   @retval EFI_INVALID_PARAMETER   Address requested is already in use.
913   @retval EFI_ACCESS_DENIED       Return access denied if the SmmReadyToLock event has been triggered
914 **/
915 EFI_STATUS
916 EFIAPI
IoTrapExRegister(IN IO_TRAP_EX_DISPATCH_PROTOCOL * This,IN IO_TRAP_EX_DISPATCH_CALLBACK DispatchFunction,IN IO_TRAP_EX_REGISTER_CONTEXT * RegisterContext,OUT EFI_HANDLE * DispatchHandle)917 IoTrapExRegister (
918   IN  IO_TRAP_EX_DISPATCH_PROTOCOL  *This,
919   IN  IO_TRAP_EX_DISPATCH_CALLBACK  DispatchFunction,
920   IN  IO_TRAP_EX_REGISTER_CONTEXT   *RegisterContext,
921   OUT EFI_HANDLE                    *DispatchHandle
922   )
923 {
924   EFI_STATUS Status;
925 
926   DEBUG ((DEBUG_INFO, "PchSmmIoTrapExRegister\n"));
927   //
928   // Return error if length is less than 4 and not power of 2.
929   //
930   if ((RegisterContext->Length < 4) || ((RegisterContext->Length & (RegisterContext->Length - 1)) != 0)) {
931     DEBUG ((DEBUG_ERROR, "The Dispatch Length is not power of 2 \n"));
932     return EFI_INVALID_PARAMETER;
933   }
934 
935   Status = IoTrapRegisterHelper (
936              DispatchHandle,
937              NULL,
938              DispatchFunction,
939              &(RegisterContext->Address),
940              RegisterContext->Length,
941              RegisterContext->Type,
942              RegisterContext->ByteEnable,
943              RegisterContext->ByteEnableMask);
944 
945   if (!EFI_ERROR (Status)) {
946     SmiHandlerProfileRegisterHandler (
947       &gIoTrapExDispatchProtocolGuid,
948       (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
949       (UINTN)RETURN_ADDRESS (0),
950       RegisterContext,
951       sizeof (*RegisterContext)
952       );
953   }
954   return Status;
955 }
956 
957 /**
958   Unregister a SMI source dispatch function.
959   This function is unsupported.
960 
961   @param[in] This                 Pointer to the IO_TRAP_EX_DISPATCH_PROTOCOL instance.
962   @param[in] DispatchHandle       Handle of dispatch function to deregister.
963 
964   @retval EFI_UNSUPPORTED         The function is unsupported.
965 **/
966 EFI_STATUS
967 EFIAPI
IoTrapExUnRegister(IN IO_TRAP_EX_DISPATCH_PROTOCOL * This,IN EFI_HANDLE DispatchHandle)968 IoTrapExUnRegister (
969   IN IO_TRAP_EX_DISPATCH_PROTOCOL   *This,
970   IN EFI_HANDLE                     DispatchHandle
971   )
972 {
973   IO_TRAP_RECORD *RecordToDelete;
974 
975   RecordToDelete = IO_TRAP_RECORD_FROM_LINK (DispatchHandle);
976   SmiHandlerProfileUnregisterHandler (
977     &gIoTrapExDispatchProtocolGuid,
978     RecordToDelete->IoTrapCallback,
979     &RecordToDelete->Context,
980     sizeof (RecordToDelete->Context)
981     );
982   return IoTrapUnRegisterHelper (DispatchHandle);
983 }
984 
985 /**
986   Pause IoTrap callback function.
987 
988   This function disables the SMI enable of IoTrap according to the DispatchHandle,
989   which is returned by IoTrap callback registration. It only supports the DispatchHandle
990   with MergeDisable TRUE and address not zero.
991 
992   NOTE: This call does not guarantee all pending IO cycles to be synchronized
993         and pending IO cycles issued before this call might not be trapped.
994 
995   @param[in] This                 Pointer to the PCH_SMM_IO_TRAP_CONTROL_PROTOCOL instance.
996   @param[in] DispatchHandle       Handle of the child service to change state.
997 
998   @retval EFI_SUCCESS             This operation is complete.
999   @retval EFI_INVALID_PARAMETER   The DispatchHandle is invalid.
1000   @retval EFI_ACCESS_DENIED       The SMI status is alrady PAUSED.
1001 **/
1002 EFI_STATUS
1003 EFIAPI
IoTrapControlPause(IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL * This,IN EFI_HANDLE DispatchHandle)1004 IoTrapControlPause (
1005   IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL   *This,
1006   IN EFI_HANDLE                         DispatchHandle
1007   )
1008 {
1009   IO_TRAP_RECORD                        *IoTrapRecord;
1010   UINT32                                IoTrapRegLowDword;
1011   UINT32                                IoTrapRegHighDword;
1012   EFI_PHYSICAL_ADDRESS                  BaseAddress;
1013   UINT32                                UsedLength;
1014   UINT8                                 TrapHandlerNum;
1015   BOOLEAN                               TempMergeDisable;
1016   BOOLEAN                               DisableIoTrap;
1017 
1018   if (DispatchHandle == 0) {
1019     return EFI_INVALID_PARAMETER;
1020   }
1021 
1022   IoTrapRecord = IO_TRAP_RECORD_FROM_LINK (DispatchHandle);
1023 
1024   if (IoTrapRecord->Context.Address) {
1025     TempMergeDisable =TRUE;
1026   }else {
1027     TempMergeDisable = FALSE;
1028   }
1029 
1030   if ((IoTrapRecord->Signature != IO_TRAP_RECORD_SIGNATURE) ||
1031       (TempMergeDisable != TRUE)                            ||
1032       (IoTrapRecord->Context.Address == 0)                  ||
1033       (IoTrapRecord->Context.Length == 0)) {
1034     return EFI_INVALID_PARAMETER;
1035   }
1036 
1037   for (TrapHandlerNum = 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; TrapHandlerNum++) {
1038     //
1039     // This IoTrap register should be merge disabled.
1040     //
1041     if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable != TRUE) {
1042       continue;
1043     }
1044     IoTrapRegLowDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8);
1045     IoTrapRegHighDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8 + 4);
1046     //
1047     // Depending on the usage, we will obtain the UsedLength and BaseAddress differently
1048     // If the registered trap length is less than 4, we obtain the length from Byte Enable Mask
1049     // In the other hand, we obtain the length from Address Mask
1050     //
1051     if (ByteEnableMaskFromHighDword (IoTrapRegHighDword) != 0xF) {
1052       UsedLength = (UINT32) (HighBitSet32 (IoTrapRegHighDword & 0xF0) - LowBitSet32 (IoTrapRegHighDword & 0xF0) + 1);
1053       BaseAddress = AddressFromLowDword (IoTrapRegLowDword) + LowBitSet32 (ByteEnableMaskFromHighDword (IoTrapRegHighDword));
1054     } else {
1055       UsedLength  = LengthFromLowDword (IoTrapRegLowDword);
1056       BaseAddress = AddressFromLowDword (IoTrapRegLowDword);
1057     }
1058 
1059     //
1060     // The address and length of record matches the IoTrap register's.
1061     //
1062     DisableIoTrap = FALSE;
1063     if ((IoTrapRecord->IoTrapExCallback != NULL) &&
1064         IsIoTrapExContentMatched (IoTrapRecord, IoTrapRegLowDword, IoTrapRegHighDword)) {
1065       DisableIoTrap = TRUE;
1066     } else if ((BaseAddress == IoTrapRecord->Context.Address) &&
1067                (UsedLength  == IoTrapRecord->Context.Length )) {
1068       DisableIoTrap = TRUE;
1069     }
1070 
1071     if (DisableIoTrap) {
1072       //
1073       // Check if status matched.
1074       // If this is already Paused, return warning status.
1075       //
1076       if ((IoTrapRegLowDword & B_PSTH_PCR_TRPREG_TSE) == 0) {
1077         return EFI_ACCESS_DENIED;
1078       }
1079       //
1080       // Clear IoTrap register SMI enable bit
1081       //
1082       IoTrapRegLowDword &= (~B_PSTH_PCR_TRPREG_TSE);
1083       SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, FALSE);
1084       //
1085       // Also clear pending IOTRAP status.
1086       //
1087       ClearPendingIoTrapStatus (TrapHandlerNum);
1088       return EFI_SUCCESS;
1089     }
1090   }
1091   return EFI_INVALID_PARAMETER;
1092 }
1093 
1094 /**
1095   Resume IoTrap callback function.
1096 
1097   This function enables the SMI enable of IoTrap according to the DispatchHandle,
1098   which is returned by IoTrap callback registration. It only supports the DispatchHandle
1099   with MergeDisable TRUE and address not zero.
1100 
1101   @param[in] This                 Pointer to the PCH_SMM_IO_TRAP_CONTROL_PROTOCOL instance.
1102   @param[in] DispatchHandle       Handle of the child service to change state.
1103 
1104   @retval EFI_SUCCESS             This operation is complete.
1105   @retval EFI_INVALID_PARAMETER   The DispatchHandle is invalid.
1106   @retval EFI_ACCESS_DENIED       The SMI status is alrady RESUMED.
1107 **/
1108 EFI_STATUS
1109 EFIAPI
IoTrapControlResume(IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL * This,IN EFI_HANDLE DispatchHandle)1110 IoTrapControlResume (
1111   IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL   *This,
1112   IN EFI_HANDLE                         DispatchHandle
1113   )
1114 {
1115   IO_TRAP_RECORD                        *IoTrapRecord;
1116   UINT32                                IoTrapRegLowDword;
1117   UINT32                                IoTrapRegHighDword;
1118   EFI_PHYSICAL_ADDRESS                  BaseAddress;
1119   UINT32                                UsedLength;
1120   UINT8                                 TrapHandlerNum;
1121   BOOLEAN                               TempMergeDisable;
1122   BOOLEAN                               EnableIoTrap;
1123 
1124   if (DispatchHandle == 0) {
1125     return EFI_INVALID_PARAMETER;
1126   }
1127   IoTrapRecord = IO_TRAP_RECORD_FROM_LINK (DispatchHandle);
1128 
1129   if (IoTrapRecord->Context.Address) {
1130     TempMergeDisable = TRUE;
1131   }else {
1132     TempMergeDisable = FALSE;
1133   }
1134 
1135   if ((IoTrapRecord->Signature != IO_TRAP_RECORD_SIGNATURE) ||
1136       (TempMergeDisable != TRUE)          ||
1137       (IoTrapRecord->Context.Address == 0)                  ||
1138       (IoTrapRecord->Context.Length == 0)) {
1139     return EFI_INVALID_PARAMETER;
1140   }
1141 
1142   for (TrapHandlerNum = 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; TrapHandlerNum++) {
1143     //
1144     // This IoTrap register should be merge disabled.
1145     //
1146     if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable != TRUE) {
1147       continue;
1148     }
1149     IoTrapRegLowDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8);
1150     IoTrapRegHighDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8 + 4);
1151     //
1152     // Depending on the usage, we will obtain the UsedLength and BaseAddress differently
1153     // If the registered trap length is less than 4, we obtain the length from Byte Enable Mask
1154     // In the other hand, we obtain the length from Address Mask
1155     //
1156     if (ByteEnableMaskFromHighDword (IoTrapRegHighDword) != 0xF) {
1157       UsedLength  = (UINT32) (HighBitSet32 (IoTrapRegHighDword & 0xF0) - LowBitSet32 (IoTrapRegHighDword & 0xF0) + 1);
1158       BaseAddress = AddressFromLowDword (IoTrapRegLowDword) + LowBitSet32 (ByteEnableMaskFromHighDword (IoTrapRegHighDword));
1159     } else {
1160       UsedLength  = LengthFromLowDword (IoTrapRegLowDword);
1161       BaseAddress = AddressFromLowDword (IoTrapRegLowDword);
1162     }
1163 
1164     //
1165     // The address and length of record matches the IoTrap register's.
1166     //
1167     EnableIoTrap = FALSE;
1168     if ((IoTrapRecord->IoTrapExCallback != NULL) &&
1169         IsIoTrapExContentMatched (IoTrapRecord, IoTrapRegLowDword, IoTrapRegHighDword)) {
1170       EnableIoTrap = TRUE;
1171     } else if ((BaseAddress == IoTrapRecord->Context.Address) &&
1172                (UsedLength  == IoTrapRecord->Context.Length )) {
1173       EnableIoTrap = TRUE;
1174     }
1175 
1176     if (EnableIoTrap) {
1177       //
1178       // Check if status matched.
1179       // If this is already Resume, return warning status.
1180       //
1181       if ((IoTrapRegLowDword & B_PSTH_PCR_TRPREG_TSE) != 0) {
1182         return EFI_ACCESS_DENIED;
1183       }
1184       //
1185       // Set IoTrap register SMI enable bit
1186       //
1187       IoTrapRegLowDword |= (B_PSTH_PCR_TRPREG_TSE);
1188       SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, FALSE);
1189       return EFI_SUCCESS;
1190     }
1191   }
1192   return EFI_INVALID_PARAMETER;
1193 }
1194 
1195 /**
1196   The IoTrap module abstracts PCH I/O trapping capabilities for other drivers.
1197   This driver manages the limited I/O trap resources.
1198 
1199   @param[in] ImageHandle                Image handle for this driver image
1200 
1201   @retval EFI_SUCCESS                   Driver initialization completed successfully
1202 **/
1203 EFI_STATUS
1204 EFIAPI
InstallIoTrap(IN EFI_HANDLE ImageHandle)1205 InstallIoTrap (
1206   IN EFI_HANDLE                         ImageHandle
1207   )
1208 {
1209   EFI_STATUS             Status;
1210   PCH_NVS_AREA_PROTOCOL  *PchNvsAreaProtocol;
1211   UINTN                  TrapHandlerNum;
1212 
1213   //
1214   // Initialize the EFI SMM driver library
1215   //
1216   mDriverImageHandle = ImageHandle;
1217 
1218   //
1219   // Initialize the IO TRAP protocol we produce
1220   //
1221   mIoTrapData.Signature = IO_TRAP_INSTANCE_SIGNATURE;
1222   mIoTrapData.EfiSmmIoTrapDispatchProtocol.Register   = IoTrapRegister;
1223   mIoTrapData.EfiSmmIoTrapDispatchProtocol.UnRegister = IoTrapUnRegister;
1224 
1225   //
1226   // Initialize the IO TRAP EX protocol
1227   //
1228   mIoTrapData.IoTrapExDispatchProtocol.Register       = IoTrapExRegister;
1229   mIoTrapData.IoTrapExDispatchProtocol.UnRegister     = IoTrapExUnRegister;
1230 
1231   //
1232   // Initialize the IO TRAP control protocol.
1233   //
1234   mIoTrapData.PchSmmIoTrapControlProtocol.Pause       = IoTrapControlPause;
1235   mIoTrapData.PchSmmIoTrapControlProtocol.Resume      = IoTrapControlResume;
1236 
1237   for (TrapHandlerNum = 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; TrapHandlerNum++) {
1238     //
1239     // Initialize IO TRAP Callback DataBase
1240     //
1241     InitializeListHead (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase));
1242   }
1243   mIoTrapData.Entry[0].CallbackDispatcher = IoTrapDispatcher0;
1244   mIoTrapData.Entry[1].CallbackDispatcher = IoTrapDispatcher1;
1245   mIoTrapData.Entry[2].CallbackDispatcher = IoTrapDispatcher2;
1246   mIoTrapData.Entry[3].CallbackDispatcher = IoTrapDispatcher3;
1247 
1248   //
1249   // Get address of PchNvs structure for later use
1250   //
1251   Status = gBS->LocateProtocol (&gPchNvsAreaProtocolGuid, NULL, (VOID **) &PchNvsAreaProtocol);
1252   ASSERT_EFI_ERROR (Status);
1253   mPchNvsArea = PchNvsAreaProtocol->Area;
1254 
1255   //
1256   // Install protocol interface
1257   //
1258   mIoTrapData.Handle = NULL;
1259   Status = gSmst->SmmInstallProtocolInterface (
1260                     &mIoTrapData.Handle,
1261                     &gEfiSmmIoTrapDispatch2ProtocolGuid,
1262                     EFI_NATIVE_INTERFACE,
1263                     &mIoTrapData.EfiSmmIoTrapDispatchProtocol
1264                     );
1265   ASSERT_EFI_ERROR (Status);
1266 
1267   Status = gSmst->SmmInstallProtocolInterface (
1268                     &mIoTrapData.Handle,
1269                     &gIoTrapExDispatchProtocolGuid,
1270                     EFI_NATIVE_INTERFACE,
1271                     &mIoTrapData.IoTrapExDispatchProtocol
1272                     );
1273   ASSERT_EFI_ERROR (Status);
1274 
1275   Status = gSmst->SmmInstallProtocolInterface (
1276                     &mIoTrapData.Handle,
1277                     &gPchSmmIoTrapControlGuid,
1278                     EFI_NATIVE_INTERFACE,
1279                     &mIoTrapData.PchSmmIoTrapControlProtocol
1280                     );
1281   ASSERT_EFI_ERROR (Status);
1282 
1283   return EFI_SUCCESS;
1284 }
1285