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