UefiCpuPkg: Update SmmCpuFeatureLib pass XCODE5 tool chain
[mirror_edk2.git] / UefiCpuPkg / Library / SmmCpuFeaturesLib / SmmStm.c
1 /** @file
2 SMM STM support functions
3
4 Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php.
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include <PiSmm.h>
16 #include <Library/BaseLib.h>
17 #include <Library/BaseMemoryLib.h>
18 #include <Library/MemoryAllocationLib.h>
19 #include <Library/HobLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 #include <Library/SmmServicesTableLib.h>
23 #include <Library/TpmMeasurementLib.h>
24 #include <Register/Cpuid.h>
25 #include <Register/ArchitecturalMsr.h>
26 #include <Register/SmramSaveStateMap.h>
27
28 #include <Protocol/MpService.h>
29
30 #include "SmmStm.h"
31
32 #define TXT_EVTYPE_BASE 0x400
33 #define TXT_EVTYPE_STM_HASH (TXT_EVTYPE_BASE + 14)
34
35 #define RDWR_ACCS 3
36 #define FULL_ACCS 7
37
38 /**
39 The constructor function
40
41 @param[in] ImageHandle The firmware allocated handle for the EFI image.
42 @param[in] SystemTable A pointer to the EFI System Table.
43
44 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
45
46 **/
47 EFI_STATUS
48 EFIAPI
49 SmmCpuFeaturesLibConstructor (
50 IN EFI_HANDLE ImageHandle,
51 IN EFI_SYSTEM_TABLE *SystemTable
52 );
53
54 EFI_HANDLE mStmSmmCpuHandle = NULL;
55
56 BOOLEAN mLockLoadMonitor = FALSE;
57
58 //
59 // Template of STM_RSC_END structure for copying.
60 //
61 GLOBAL_REMOVE_IF_UNREFERENCED STM_RSC_END mRscEndNode = {
62 {END_OF_RESOURCES, sizeof (STM_RSC_END)},
63 };
64
65 GLOBAL_REMOVE_IF_UNREFERENCED UINT8 *mStmResourcesPtr = NULL;
66 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mStmResourceTotalSize = 0x0;
67 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mStmResourceSizeUsed = 0x0;
68 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mStmResourceSizeAvailable = 0x0;
69
70 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mStmState = 0;
71
72 //
73 // System Configuration Table pointing to STM Configuration Table
74 //
75 GLOBAL_REMOVE_IF_UNREFERENCED
76 EFI_SM_MONITOR_INIT_PROTOCOL mSmMonitorInitProtocol = {
77 LoadMonitor,
78 AddPiResource,
79 DeletePiResource,
80 GetPiResource,
81 GetMonitorState,
82 };
83
84
85
86
87 #define CPUID1_EDX_XD_SUPPORT 0x100000
88
89 //
90 // External global variables associated with SMI Handler Template
91 //
92 extern CONST TXT_PROCESSOR_SMM_DESCRIPTOR gcStmPsd;
93 extern UINT32 gStmSmbase;
94 extern volatile UINT32 gStmSmiStack;
95 extern UINT32 gStmSmiCr3;
96 extern volatile UINT8 gcStmSmiHandlerTemplate[];
97 extern CONST UINT16 gcStmSmiHandlerSize;
98 extern UINT16 gcStmSmiHandlerOffset;
99 extern BOOLEAN gStmXdSupported;
100
101 //
102 // Variables used by SMI Handler
103 //
104 IA32_DESCRIPTOR gStmSmiHandlerIdtr;
105
106 //
107 // MP Services Protocol
108 //
109 EFI_MP_SERVICES_PROTOCOL *mSmmCpuFeaturesLibMpService = NULL;
110
111 //
112 // MSEG Base and Length in SMRAM
113 //
114 UINTN mMsegBase = 0;
115 UINTN mMsegSize = 0;
116
117 BOOLEAN mStmConfigurationTableInitialized = FALSE;
118
119 /**
120 The constructor function
121
122 @param[in] ImageHandle The firmware allocated handle for the EFI image.
123 @param[in] SystemTable A pointer to the EFI System Table.
124
125 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
126
127 **/
128 EFI_STATUS
129 EFIAPI
130 SmmCpuFeaturesLibStmConstructor (
131 IN EFI_HANDLE ImageHandle,
132 IN EFI_SYSTEM_TABLE *SystemTable
133 )
134 {
135 EFI_STATUS Status;
136 CPUID_VERSION_INFO_ECX RegEcx;
137 EFI_HOB_GUID_TYPE *GuidHob;
138 EFI_SMRAM_DESCRIPTOR *SmramDescriptor;
139
140 //
141 // Initialize address fixup
142 //
143 SmmCpuFeaturesLibStmSmiEntryFixupAddress ();
144
145 //
146 // Call the common constructor function
147 //
148 Status = SmmCpuFeaturesLibConstructor (ImageHandle, SystemTable);
149 ASSERT_EFI_ERROR (Status);
150
151 //
152 // Lookup the MP Services Protocol
153 //
154 Status = gBS->LocateProtocol (
155 &gEfiMpServiceProtocolGuid,
156 NULL,
157 (VOID **)&mSmmCpuFeaturesLibMpService
158 );
159 ASSERT_EFI_ERROR (Status);
160
161 //
162 // If CPU supports VMX, then determine SMRAM range for MSEG.
163 //
164 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &RegEcx.Uint32, NULL);
165 if (RegEcx.Bits.VMX == 1) {
166 GuidHob = GetFirstGuidHob (&gMsegSmramGuid);
167 if (GuidHob != NULL) {
168 //
169 // Retrieve MSEG location from MSEG SRAM HOB
170 //
171 SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob);
172 if (SmramDescriptor->PhysicalSize > 0) {
173 mMsegBase = (UINTN)SmramDescriptor->CpuStart;
174 mMsegSize = (UINTN)SmramDescriptor->PhysicalSize;
175 }
176 } else if (PcdGet32 (PcdCpuMsegSize) > 0) {
177 //
178 // Allocate MSEG from SMRAM memory
179 //
180 mMsegBase = (UINTN)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuMsegSize)));
181 if (mMsegBase > 0) {
182 mMsegSize = ALIGN_VALUE (PcdGet32 (PcdCpuMsegSize), EFI_PAGE_SIZE);
183 } else {
184 DEBUG ((DEBUG_ERROR, "Not enough SMRAM resource to allocate MSEG size %08x\n", PcdGet32 (PcdCpuMsegSize)));
185 }
186 }
187 if (mMsegBase > 0) {
188 DEBUG ((DEBUG_INFO, "MsegBase: 0x%08x, MsegSize: 0x%08x\n", mMsegBase, mMsegSize));
189 }
190 }
191
192 return EFI_SUCCESS;
193 }
194
195 /**
196 Internal worker function that is called to complete CPU initialization at the
197 end of SmmCpuFeaturesInitializeProcessor().
198
199 **/
200 VOID
201 FinishSmmCpuFeaturesInitializeProcessor (
202 VOID
203 )
204 {
205 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl;
206
207 //
208 // Set MSEG Base Address in SMM Monitor Control MSR.
209 //
210 if (mMsegBase > 0) {
211 SmmMonitorCtl.Uint64 = 0;
212 SmmMonitorCtl.Bits.MsegBase = (UINT32)mMsegBase >> 12;
213 SmmMonitorCtl.Bits.Valid = 1;
214 AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL, SmmMonitorCtl.Uint64);
215 }
216 }
217
218 /**
219 Return the size, in bytes, of a custom SMI Handler in bytes. If 0 is
220 returned, then a custom SMI handler is not provided by this library,
221 and the default SMI handler must be used.
222
223 @retval 0 Use the default SMI handler.
224 @retval > 0 Use the SMI handler installed by SmmCpuFeaturesInstallSmiHandler()
225 The caller is required to allocate enough SMRAM for each CPU to
226 support the size of the custom SMI handler.
227 **/
228 UINTN
229 EFIAPI
230 SmmCpuFeaturesGetSmiHandlerSize (
231 VOID
232 )
233 {
234 return gcStmSmiHandlerSize;
235 }
236
237 /**
238 Install a custom SMI handler for the CPU specified by CpuIndex. This function
239 is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size is greater
240 than zero and is called by the CPU that was elected as monarch during System
241 Management Mode initialization.
242
243 @param[in] CpuIndex The index of the CPU to install the custom SMI handler.
244 The value must be between 0 and the NumberOfCpus field
245 in the System Management System Table (SMST).
246 @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.
247 @param[in] SmiStack The stack to use when an SMI is processed by the
248 the CPU specified by CpuIndex.
249 @param[in] StackSize The size, in bytes, if the stack used when an SMI is
250 processed by the CPU specified by CpuIndex.
251 @param[in] GdtBase The base address of the GDT to use when an SMI is
252 processed by the CPU specified by CpuIndex.
253 @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is
254 processed by the CPU specified by CpuIndex.
255 @param[in] IdtBase The base address of the IDT to use when an SMI is
256 processed by the CPU specified by CpuIndex.
257 @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is
258 processed by the CPU specified by CpuIndex.
259 @param[in] Cr3 The base address of the page tables to use when an SMI
260 is processed by the CPU specified by CpuIndex.
261 **/
262 VOID
263 EFIAPI
264 SmmCpuFeaturesInstallSmiHandler (
265 IN UINTN CpuIndex,
266 IN UINT32 SmBase,
267 IN VOID *SmiStack,
268 IN UINTN StackSize,
269 IN UINTN GdtBase,
270 IN UINTN GdtSize,
271 IN UINTN IdtBase,
272 IN UINTN IdtSize,
273 IN UINT32 Cr3
274 )
275 {
276 EFI_STATUS Status;
277 TXT_PROCESSOR_SMM_DESCRIPTOR *Psd;
278 VOID *Hob;
279 UINT32 RegEax;
280 UINT32 RegEdx;
281 EFI_PROCESSOR_INFORMATION ProcessorInfo;
282
283 CopyMem ((VOID *)((UINTN)SmBase + TXT_SMM_PSD_OFFSET), &gcStmPsd, sizeof (gcStmPsd));
284 Psd = (TXT_PROCESSOR_SMM_DESCRIPTOR *)(VOID *)((UINTN)SmBase + TXT_SMM_PSD_OFFSET);
285 Psd->SmmGdtPtr = GdtBase;
286 Psd->SmmGdtSize = (UINT32)GdtSize;
287
288 //
289 // Initialize values in template before copy
290 //
291 gStmSmiStack = (UINT32)((UINTN)SmiStack + StackSize - sizeof (UINTN));
292 gStmSmiCr3 = Cr3;
293 gStmSmbase = SmBase;
294 gStmSmiHandlerIdtr.Base = IdtBase;
295 gStmSmiHandlerIdtr.Limit = (UINT16)(IdtSize - 1);
296
297 if (gStmXdSupported) {
298 AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);
299 if (RegEax <= CPUID_EXTENDED_FUNCTION) {
300 //
301 // Extended CPUID functions are not supported on this processor.
302 //
303 gStmXdSupported = FALSE;
304 }
305
306 AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx);
307 if ((RegEdx & CPUID1_EDX_XD_SUPPORT) == 0) {
308 //
309 // Execute Disable Bit feature is not supported on this processor.
310 //
311 gStmXdSupported = FALSE;
312 }
313 }
314
315 //
316 // Set the value at the top of the CPU stack to the CPU Index
317 //
318 *(UINTN*)(UINTN)gStmSmiStack = CpuIndex;
319
320 //
321 // Copy template to CPU specific SMI handler location
322 //
323 CopyMem (
324 (VOID*)((UINTN)SmBase + SMM_HANDLER_OFFSET),
325 (VOID*)gcStmSmiHandlerTemplate,
326 gcStmSmiHandlerSize
327 );
328
329 Psd->SmmSmiHandlerRip = SmBase + SMM_HANDLER_OFFSET + gcStmSmiHandlerOffset;
330 Psd->SmmSmiHandlerRsp = (UINTN)SmiStack + StackSize - sizeof(UINTN);
331 Psd->SmmCr3 = Cr3;
332
333 DEBUG((DEBUG_INFO, "CpuSmmStmExceptionStackSize - %x\n", PcdGet32(PcdCpuSmmStmExceptionStackSize)));
334 DEBUG((DEBUG_INFO, "Pages - %x\n", EFI_SIZE_TO_PAGES(PcdGet32(PcdCpuSmmStmExceptionStackSize))));
335 Psd->StmProtectionExceptionHandler.SpeRsp = (UINT64)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize)));
336 Psd->StmProtectionExceptionHandler.SpeRsp += EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize)));
337
338 Psd->BiosHwResourceRequirementsPtr = (UINT64)(UINTN)GetStmResource ();
339
340 //
341 // Get the APIC ID for the CPU specified by CpuIndex
342 //
343 Status = mSmmCpuFeaturesLibMpService->GetProcessorInfo (
344 mSmmCpuFeaturesLibMpService,
345 CpuIndex,
346 &ProcessorInfo
347 );
348 ASSERT_EFI_ERROR (Status);
349
350 Psd->LocalApicId = (UINT32)ProcessorInfo.ProcessorId;
351 Psd->AcpiRsdp = 0;
352
353 Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
354 if (Hob != NULL) {
355 Psd->PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
356 } else {
357 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
358 if (RegEax >= 0x80000008) {
359 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
360 Psd->PhysicalAddressBits = (UINT8) RegEax;
361 } else {
362 Psd->PhysicalAddressBits = 36;
363 }
364 }
365
366 if (!mStmConfigurationTableInitialized) {
367 StmSmmConfigurationTableInit ();
368 mStmConfigurationTableInitialized = TRUE;
369 }
370 }
371
372 /**
373 SMM End Of Dxe event notification handler.
374
375 STM support need patch AcpiRsdp in TXT_PROCESSOR_SMM_DESCRIPTOR.
376
377 @param[in] Protocol Points to the protocol's unique identifier.
378 @param[in] Interface Points to the interface instance.
379 @param[in] Handle The handle on which the interface was installed.
380
381 @retval EFI_SUCCESS Notification handler runs successfully.
382 **/
383 EFI_STATUS
384 EFIAPI
385 SmmEndOfDxeEventNotify (
386 IN CONST EFI_GUID *Protocol,
387 IN VOID *Interface,
388 IN EFI_HANDLE Handle
389 )
390 {
391 VOID *Rsdp;
392 UINTN Index;
393 TXT_PROCESSOR_SMM_DESCRIPTOR *Psd;
394
395 DEBUG ((DEBUG_INFO, "SmmEndOfDxeEventNotify\n"));
396
397 //
398 // found ACPI table RSD_PTR from system table
399 //
400 Rsdp = NULL;
401 for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
402 if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpi20TableGuid)) {
403 //
404 // A match was found.
405 //
406 Rsdp = gST->ConfigurationTable[Index].VendorTable;
407 break;
408 }
409 }
410 if (Rsdp == NULL) {
411 for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
412 if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpi10TableGuid)) {
413 //
414 // A match was found.
415 //
416 Rsdp = gST->ConfigurationTable[Index].VendorTable;
417 break;
418 }
419 }
420 }
421
422 for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
423 Psd = (TXT_PROCESSOR_SMM_DESCRIPTOR *)((UINTN)gSmst->CpuSaveState[Index] - SMRAM_SAVE_STATE_MAP_OFFSET + TXT_SMM_PSD_OFFSET);
424 DEBUG ((DEBUG_INFO, "Index=%d Psd=%p Rsdp=%p\n", Index, Psd, Rsdp));
425 Psd->AcpiRsdp = (UINT64)(UINTN)Rsdp;
426 }
427
428 mLockLoadMonitor = TRUE;
429
430 return EFI_SUCCESS;
431 }
432
433 /**
434 This function initializes the STM configuration table.
435 **/
436 VOID
437 StmSmmConfigurationTableInit (
438 VOID
439 )
440 {
441 EFI_STATUS Status;
442 VOID *Registration;
443
444 Status = gSmst->SmmInstallProtocolInterface (
445 &mStmSmmCpuHandle,
446 &gEfiSmMonitorInitProtocolGuid,
447 EFI_NATIVE_INTERFACE,
448 &mSmMonitorInitProtocol
449 );
450 ASSERT_EFI_ERROR (Status);
451
452 //
453 //
454 // Register SMM End of DXE Event
455 //
456 Status = gSmst->SmmRegisterProtocolNotify (
457 &gEfiSmmEndOfDxeProtocolGuid,
458 SmmEndOfDxeEventNotify,
459 &Registration
460 );
461 ASSERT_EFI_ERROR (Status);
462 }
463
464 /**
465
466 Get STM state.
467
468 @return STM state
469
470 **/
471 EFI_SM_MONITOR_STATE
472 EFIAPI
473 GetMonitorState (
474 VOID
475 )
476 {
477 return mStmState;
478 }
479
480 /**
481
482 Handle single Resource to see if it can be merged into Record.
483
484 @param Resource A pointer to resource node to be added
485 @param Record A pointer to record node to be merged
486
487 @retval TRUE resource handled
488 @retval FALSE resource is not handled
489
490 **/
491 BOOLEAN
492 HandleSingleResource (
493 IN STM_RSC *Resource,
494 IN STM_RSC *Record
495 )
496 {
497 UINT64 ResourceLo;
498 UINT64 ResourceHi;
499 UINT64 RecordLo;
500 UINT64 RecordHi;
501
502 ResourceLo = 0;
503 ResourceHi = 0;
504 RecordLo = 0;
505 RecordHi = 0;
506
507 //
508 // Calling code is responsible for making sure that
509 // Resource->Header.RscType == (*Record)->Header.RscType
510 // thus we use just one of them as switch variable.
511 //
512 switch (Resource->Header.RscType) {
513 case MEM_RANGE:
514 case MMIO_RANGE:
515 ResourceLo = Resource->Mem.Base;
516 ResourceHi = Resource->Mem.Base + Resource->Mem.Length;
517 RecordLo = Record->Mem.Base;
518 RecordHi = Record->Mem.Base + Record->Mem.Length;
519 if (Resource->Mem.RWXAttributes != Record->Mem.RWXAttributes) {
520 if ((ResourceLo == RecordLo) && (ResourceHi == RecordHi)) {
521 Record->Mem.RWXAttributes = Resource->Mem.RWXAttributes | Record->Mem.RWXAttributes;
522 return TRUE;
523 } else {
524 return FALSE;
525 }
526 }
527 break;
528 case IO_RANGE:
529 case TRAPPED_IO_RANGE:
530 ResourceLo = (UINT64) Resource->Io.Base;
531 ResourceHi = (UINT64) Resource->Io.Base + (UINT64) Resource->Io.Length;
532 RecordLo = (UINT64) Record->Io.Base;
533 RecordHi = (UINT64) Record->Io.Base + (UINT64) Record->Io.Length;
534 break;
535 case PCI_CFG_RANGE:
536 if ((Resource->PciCfg.OriginatingBusNumber != Record->PciCfg.OriginatingBusNumber) ||
537 (Resource->PciCfg.LastNodeIndex != Record->PciCfg.LastNodeIndex)) {
538 return FALSE;
539 }
540 if (CompareMem (Resource->PciCfg.PciDevicePath, Record->PciCfg.PciDevicePath, sizeof(STM_PCI_DEVICE_PATH_NODE) * (Resource->PciCfg.LastNodeIndex + 1)) != 0) {
541 return FALSE;
542 }
543 ResourceLo = (UINT64) Resource->PciCfg.Base;
544 ResourceHi = (UINT64) Resource->PciCfg.Base + (UINT64) Resource->PciCfg.Length;
545 RecordLo = (UINT64) Record->PciCfg.Base;
546 RecordHi = (UINT64) Record->PciCfg.Base + (UINT64) Record->PciCfg.Length;
547 if (Resource->PciCfg.RWAttributes != Record->PciCfg.RWAttributes) {
548 if ((ResourceLo == RecordLo) && (ResourceHi == RecordHi)) {
549 Record->PciCfg.RWAttributes = Resource->PciCfg.RWAttributes | Record->PciCfg.RWAttributes;
550 return TRUE;
551 } else {
552 return FALSE;
553 }
554 }
555 break;
556 case MACHINE_SPECIFIC_REG:
557 //
558 // Special case - merge MSR masks in place.
559 //
560 if (Resource->Msr.MsrIndex != Record->Msr.MsrIndex) {
561 return FALSE;
562 }
563 Record->Msr.ReadMask |= Resource->Msr.ReadMask;
564 Record->Msr.WriteMask |= Resource->Msr.WriteMask;
565 return TRUE;
566 default:
567 return FALSE;
568 }
569 //
570 // If resources are disjoint
571 //
572 if ((ResourceHi < RecordLo) || (ResourceLo > RecordHi)) {
573 return FALSE;
574 }
575
576 //
577 // If resource is consumed by record.
578 //
579 if ((ResourceLo >= RecordLo) && (ResourceHi <= RecordHi)) {
580 return TRUE;
581 }
582 //
583 // Resources are overlapping.
584 // Resource and record are merged.
585 //
586 ResourceLo = (ResourceLo < RecordLo) ? ResourceLo : RecordLo;
587 ResourceHi = (ResourceHi > RecordHi) ? ResourceHi : RecordHi;
588
589 switch (Resource->Header.RscType) {
590 case MEM_RANGE:
591 case MMIO_RANGE:
592 Record->Mem.Base = ResourceLo;
593 Record->Mem.Length = ResourceHi - ResourceLo;
594 break;
595 case IO_RANGE:
596 case TRAPPED_IO_RANGE:
597 Record->Io.Base = (UINT16) ResourceLo;
598 Record->Io.Length = (UINT16) (ResourceHi - ResourceLo);
599 break;
600 case PCI_CFG_RANGE:
601 Record->PciCfg.Base = (UINT16) ResourceLo;
602 Record->PciCfg.Length = (UINT16) (ResourceHi - ResourceLo);
603 break;
604 default:
605 return FALSE;
606 }
607
608 return TRUE;
609 }
610
611 /**
612
613 Add resource node.
614
615 @param Resource A pointer to resource node to be added
616
617 **/
618 VOID
619 AddSingleResource (
620 IN STM_RSC *Resource
621 )
622 {
623 STM_RSC *Record;
624
625 Record = (STM_RSC *)mStmResourcesPtr;
626
627 while (TRUE) {
628 if (Record->Header.RscType == END_OF_RESOURCES) {
629 break;
630 }
631 //
632 // Go to next record if resource and record types don't match.
633 //
634 if (Resource->Header.RscType != Record->Header.RscType) {
635 Record = (STM_RSC *)((UINTN)Record + Record->Header.Length);
636 continue;
637 }
638 //
639 // Record is handled inside of procedure - don't adjust.
640 //
641 if (HandleSingleResource (Resource, Record)) {
642 return ;
643 }
644 Record = (STM_RSC *)((UINTN)Record + Record->Header.Length);
645 }
646
647 //
648 // Add resource to the end of area.
649 //
650 CopyMem (
651 mStmResourcesPtr + mStmResourceSizeUsed - sizeof(mRscEndNode),
652 Resource,
653 Resource->Header.Length
654 );
655 CopyMem (
656 mStmResourcesPtr + mStmResourceSizeUsed - sizeof(mRscEndNode) + Resource->Header.Length,
657 &mRscEndNode,
658 sizeof(mRscEndNode)
659 );
660 mStmResourceSizeUsed += Resource->Header.Length;
661 mStmResourceSizeAvailable = mStmResourceTotalSize - mStmResourceSizeUsed;
662
663 return ;
664 }
665
666 /**
667
668 Add resource list.
669
670 @param ResourceList A pointer to resource list to be added
671 @param NumEntries Optional number of entries.
672 If 0, list must be terminated by END_OF_RESOURCES.
673
674 **/
675 VOID
676 AddResource (
677 IN STM_RSC *ResourceList,
678 IN UINT32 NumEntries OPTIONAL
679 )
680 {
681 UINT32 Count;
682 UINTN Index;
683 STM_RSC *Resource;
684
685 if (NumEntries == 0) {
686 Count = 0xFFFFFFFF;
687 } else {
688 Count = NumEntries;
689 }
690
691 Resource = ResourceList;
692
693 for (Index = 0; Index < Count; Index++) {
694 if (Resource->Header.RscType == END_OF_RESOURCES) {
695 return ;
696 }
697 AddSingleResource (Resource);
698 Resource = (STM_RSC *)((UINTN)Resource + Resource->Header.Length);
699 }
700 return ;
701 }
702
703 /**
704
705 Validate resource list.
706
707 @param ResourceList A pointer to resource list to be added
708 @param NumEntries Optional number of entries.
709 If 0, list must be terminated by END_OF_RESOURCES.
710
711 @retval TRUE resource valid
712 @retval FALSE resource invalid
713
714 **/
715 BOOLEAN
716 ValidateResource (
717 IN STM_RSC *ResourceList,
718 IN UINT32 NumEntries OPTIONAL
719 )
720 {
721 UINT32 Count;
722 UINTN Index;
723 STM_RSC *Resource;
724 UINTN SubIndex;
725
726 //
727 // If NumEntries == 0 make it very big. Scan will be terminated by
728 // END_OF_RESOURCES.
729 //
730 if (NumEntries == 0) {
731 Count = 0xFFFFFFFF;
732 } else {
733 Count = NumEntries;
734 }
735
736 //
737 // Start from beginning of resource list.
738 //
739 Resource = ResourceList;
740
741 for (Index = 0; Index < Count; Index++) {
742 DEBUG ((DEBUG_INFO, "ValidateResource (%d) - RscType(%x)\n", Index, Resource->Header.RscType));
743 //
744 // Validate resource.
745 //
746 switch (Resource->Header.RscType) {
747 case END_OF_RESOURCES:
748 if (Resource->Header.Length != sizeof (STM_RSC_END)) {
749 return FALSE;
750 }
751 //
752 // If we are passed actual number of resources to add,
753 // END_OF_RESOURCES structure between them is considered an
754 // error. If NumEntries == 0 END_OF_RESOURCES is a termination.
755 //
756 if (NumEntries != 0) {
757 return FALSE;
758 } else {
759 //
760 // If NumEntries == 0 and list reached end - return success.
761 //
762 return TRUE;
763 }
764 break;
765
766 case MEM_RANGE:
767 case MMIO_RANGE:
768 if (Resource->Header.Length != sizeof (STM_RSC_MEM_DESC)) {
769 return FALSE;
770 }
771
772 if (Resource->Mem.RWXAttributes > FULL_ACCS) {
773 return FALSE;
774 }
775 break;
776
777 case IO_RANGE:
778 case TRAPPED_IO_RANGE:
779 if (Resource->Header.Length != sizeof (STM_RSC_IO_DESC)) {
780 return FALSE;
781 }
782
783 if ((Resource->Io.Base + Resource->Io.Length) > 0xFFFF) {
784 return FALSE;
785 }
786 break;
787
788 case PCI_CFG_RANGE:
789 DEBUG ((DEBUG_INFO, "ValidateResource - PCI (0x%02x, 0x%08x, 0x%02x, 0x%02x)\n", Resource->PciCfg.OriginatingBusNumber, Resource->PciCfg.LastNodeIndex, Resource->PciCfg.PciDevicePath[0].PciDevice, Resource->PciCfg.PciDevicePath[0].PciFunction));
790 if (Resource->Header.Length != sizeof (STM_RSC_PCI_CFG_DESC) + (sizeof(STM_PCI_DEVICE_PATH_NODE) * Resource->PciCfg.LastNodeIndex)) {
791 return FALSE;
792 }
793 for (SubIndex = 0; SubIndex <= Resource->PciCfg.LastNodeIndex; SubIndex++) {
794 if ((Resource->PciCfg.PciDevicePath[SubIndex].PciDevice > 0x1F) || (Resource->PciCfg.PciDevicePath[SubIndex].PciFunction > 7)) {
795 return FALSE;
796 }
797 }
798 if ((Resource->PciCfg.Base + Resource->PciCfg.Length) > 0x1000) {
799 return FALSE;
800 }
801 break;
802
803 case MACHINE_SPECIFIC_REG:
804 if (Resource->Header.Length != sizeof (STM_RSC_MSR_DESC)) {
805 return FALSE;
806 }
807 break;
808
809 default :
810 DEBUG ((DEBUG_ERROR, "ValidateResource - Unknown RscType(%x)\n", Resource->Header.RscType));
811 return FALSE;
812 }
813 Resource = (STM_RSC *)((UINTN)Resource + Resource->Header.Length);
814 }
815 return TRUE;
816 }
817
818 /**
819
820 Get resource list.
821 EndResource is excluded.
822
823 @param ResourceList A pointer to resource list to be added
824 @param NumEntries Optional number of entries.
825 If 0, list must be terminated by END_OF_RESOURCES.
826
827 @retval TRUE resource valid
828 @retval FALSE resource invalid
829
830 **/
831 UINTN
832 GetResourceSize (
833 IN STM_RSC *ResourceList,
834 IN UINT32 NumEntries OPTIONAL
835 )
836 {
837 UINT32 Count;
838 UINTN Index;
839 STM_RSC *Resource;
840
841 Resource = ResourceList;
842
843 //
844 // If NumEntries == 0 make it very big. Scan will be terminated by
845 // END_OF_RESOURCES.
846 //
847 if (NumEntries == 0) {
848 Count = 0xFFFFFFFF;
849 } else {
850 Count = NumEntries;
851 }
852
853 //
854 // Start from beginning of resource list.
855 //
856 Resource = ResourceList;
857
858 for (Index = 0; Index < Count; Index++) {
859 if (Resource->Header.RscType == END_OF_RESOURCES) {
860 break;
861 }
862 Resource = (STM_RSC *)((UINTN)Resource + Resource->Header.Length);
863 }
864
865 return (UINTN)Resource - (UINTN)ResourceList;
866 }
867
868 /**
869
870 Add resources in list to database. Allocate new memory areas as needed.
871
872 @param ResourceList A pointer to resource list to be added
873 @param NumEntries Optional number of entries.
874 If 0, list must be terminated by END_OF_RESOURCES.
875
876 @retval EFI_SUCCESS If resources are added
877 @retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
878 @retval EFI_OUT_OF_RESOURCES If nested procedure returned it and we cannot allocate more areas.
879
880 **/
881 EFI_STATUS
882 EFIAPI
883 AddPiResource (
884 IN STM_RSC *ResourceList,
885 IN UINT32 NumEntries OPTIONAL
886 )
887 {
888 EFI_STATUS Status;
889 UINTN ResourceSize;
890 EFI_PHYSICAL_ADDRESS NewResource;
891 UINTN NewResourceSize;
892
893 DEBUG ((DEBUG_INFO, "AddPiResource - Enter\n"));
894
895 if (!ValidateResource (ResourceList, NumEntries)) {
896 return EFI_INVALID_PARAMETER;
897 }
898
899 ResourceSize = GetResourceSize (ResourceList, NumEntries);
900 DEBUG ((DEBUG_INFO, "ResourceSize - 0x%08x\n", ResourceSize));
901 if (ResourceSize == 0) {
902 return EFI_INVALID_PARAMETER;
903 }
904
905 if (mStmResourcesPtr == NULL) {
906 //
907 // First time allocation
908 //
909 NewResourceSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (ResourceSize + sizeof(mRscEndNode)));
910 DEBUG ((DEBUG_INFO, "Allocate - 0x%08x\n", NewResourceSize));
911 Status = gSmst->SmmAllocatePages (
912 AllocateAnyPages,
913 EfiRuntimeServicesData,
914 EFI_SIZE_TO_PAGES (NewResourceSize),
915 &NewResource
916 );
917 if (EFI_ERROR (Status)) {
918 return Status;
919 }
920
921 //
922 // Copy EndResource for intialization
923 //
924 mStmResourcesPtr = (UINT8 *)(UINTN)NewResource;
925 mStmResourceTotalSize = NewResourceSize;
926 CopyMem (mStmResourcesPtr, &mRscEndNode, sizeof(mRscEndNode));
927 mStmResourceSizeUsed = sizeof(mRscEndNode);
928 mStmResourceSizeAvailable = mStmResourceTotalSize - sizeof(mRscEndNode);
929
930 //
931 // Let SmmCore change resource ptr
932 //
933 NotifyStmResourceChange (mStmResourcesPtr);
934 } else if (mStmResourceSizeAvailable < ResourceSize) {
935 //
936 // Need enlarge
937 //
938 NewResourceSize = mStmResourceTotalSize + (ResourceSize - mStmResourceSizeAvailable);
939 NewResourceSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (NewResourceSize));
940 DEBUG ((DEBUG_INFO, "ReAllocate - 0x%08x\n", NewResourceSize));
941 Status = gSmst->SmmAllocatePages (
942 AllocateAnyPages,
943 EfiRuntimeServicesData,
944 EFI_SIZE_TO_PAGES (NewResourceSize),
945 &NewResource
946 );
947 if (EFI_ERROR (Status)) {
948 return Status;
949 }
950 CopyMem ((VOID *)(UINTN)NewResource, mStmResourcesPtr, mStmResourceSizeUsed);
951 mStmResourceSizeAvailable = NewResourceSize - mStmResourceSizeUsed;
952
953 gSmst->SmmFreePages (
954 (EFI_PHYSICAL_ADDRESS)(UINTN)mStmResourcesPtr,
955 EFI_SIZE_TO_PAGES (mStmResourceTotalSize)
956 );
957
958 mStmResourceTotalSize = NewResourceSize;
959 mStmResourcesPtr = (UINT8 *)(UINTN)NewResource;
960
961 //
962 // Let SmmCore change resource ptr
963 //
964 NotifyStmResourceChange (mStmResourcesPtr);
965 }
966
967 //
968 // Check duplication
969 //
970 AddResource (ResourceList, NumEntries);
971
972 return EFI_SUCCESS;
973 }
974
975 /**
976
977 Delete resources in list to database.
978
979 @param ResourceList A pointer to resource list to be deleted
980 NULL means delete all resources.
981 @param NumEntries Optional number of entries.
982 If 0, list must be terminated by END_OF_RESOURCES.
983
984 @retval EFI_SUCCESS If resources are deleted
985 @retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
986
987 **/
988 EFI_STATUS
989 EFIAPI
990 DeletePiResource (
991 IN STM_RSC *ResourceList,
992 IN UINT32 NumEntries OPTIONAL
993 )
994 {
995 if (ResourceList != NULL) {
996 // TBD
997 ASSERT (FALSE);
998 return EFI_UNSUPPORTED;
999 }
1000 //
1001 // Delete all
1002 //
1003 CopyMem (mStmResourcesPtr, &mRscEndNode, sizeof(mRscEndNode));
1004 mStmResourceSizeUsed = sizeof(mRscEndNode);
1005 mStmResourceSizeAvailable = mStmResourceTotalSize - sizeof(mRscEndNode);
1006 return EFI_SUCCESS;
1007 }
1008
1009 /**
1010
1011 Get BIOS resources.
1012
1013 @param ResourceList A pointer to resource list to be filled
1014 @param ResourceSize On input it means size of resource list input.
1015 On output it means size of resource list filled,
1016 or the size of resource list to be filled if size of too small.
1017
1018 @retval EFI_SUCCESS If resources are returned.
1019 @retval EFI_BUFFER_TOO_SMALL If resource list buffer is too small to hold the whole resources.
1020
1021 **/
1022 EFI_STATUS
1023 EFIAPI
1024 GetPiResource (
1025 OUT STM_RSC *ResourceList,
1026 IN OUT UINT32 *ResourceSize
1027 )
1028 {
1029 if (*ResourceSize < mStmResourceSizeUsed) {
1030 *ResourceSize = (UINT32)mStmResourceSizeUsed;
1031 return EFI_BUFFER_TOO_SMALL;
1032 }
1033
1034 CopyMem (ResourceList, mStmResourcesPtr, mStmResourceSizeUsed);
1035 *ResourceSize = (UINT32)mStmResourceSizeUsed;
1036 return EFI_SUCCESS;
1037 }
1038
1039 /**
1040
1041 Set valid bit for MSEG MSR.
1042
1043 @param Buffer Ap function buffer. (not used)
1044
1045 **/
1046 VOID
1047 EFIAPI
1048 EnableMsegMsr (
1049 IN VOID *Buffer
1050 )
1051 {
1052 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl;
1053
1054 SmmMonitorCtl.Uint64 = AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL);
1055 SmmMonitorCtl.Bits.Valid = 1;
1056 AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL, SmmMonitorCtl.Uint64);
1057 }
1058
1059 /**
1060
1061 Get 4K page aligned VMCS size.
1062
1063 @return 4K page aligned VMCS size
1064
1065 **/
1066 UINT32
1067 GetVmcsSize (
1068 VOID
1069 )
1070 {
1071 MSR_IA32_VMX_BASIC_REGISTER VmxBasic;
1072
1073 //
1074 // Read VMCS size and and align to 4KB
1075 //
1076 VmxBasic.Uint64 = AsmReadMsr64 (MSR_IA32_VMX_BASIC);
1077 return ALIGN_VALUE (VmxBasic.Bits.VmcsSize, SIZE_4KB);
1078 }
1079
1080 /**
1081
1082 Check STM image size.
1083
1084 @param StmImage STM image
1085 @param StmImageSize STM image size
1086
1087 @retval TRUE check pass
1088 @retval FALSE check fail
1089 **/
1090 BOOLEAN
1091 StmCheckStmImage (
1092 IN EFI_PHYSICAL_ADDRESS StmImage,
1093 IN UINTN StmImageSize
1094 )
1095 {
1096 UINTN MinMsegSize;
1097 STM_HEADER *StmHeader;
1098 IA32_VMX_MISC_REGISTER VmxMiscMsr;
1099
1100 //
1101 // Check to see if STM image is compatible with CPU
1102 //
1103 StmHeader = (STM_HEADER *)(UINTN)StmImage;
1104 VmxMiscMsr.Uint64 = AsmReadMsr64 (MSR_IA32_VMX_MISC);
1105 if (StmHeader->HwStmHdr.MsegHeaderRevision != VmxMiscMsr.Bits.MsegRevisionIdentifier) {
1106 DEBUG ((DEBUG_ERROR, "STM Image not compatible with CPU\n"));
1107 DEBUG ((DEBUG_ERROR, " StmHeader->HwStmHdr.MsegHeaderRevision = %08x\n", StmHeader->HwStmHdr.MsegHeaderRevision));
1108 DEBUG ((DEBUG_ERROR, " VmxMiscMsr.Bits.MsegRevisionIdentifier = %08x\n", VmxMiscMsr.Bits.MsegRevisionIdentifier));
1109 return FALSE;
1110 }
1111
1112 //
1113 // Get Minimal required Mseg size
1114 //
1115 MinMsegSize = (EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (StmHeader->SwStmHdr.StaticImageSize)) +
1116 StmHeader->SwStmHdr.AdditionalDynamicMemorySize +
1117 (StmHeader->SwStmHdr.PerProcDynamicMemorySize + GetVmcsSize () * 2) * gSmst->NumberOfCpus);
1118 if (MinMsegSize < StmImageSize) {
1119 MinMsegSize = StmImageSize;
1120 }
1121
1122 if (StmHeader->HwStmHdr.Cr3Offset >= StmHeader->SwStmHdr.StaticImageSize) {
1123 //
1124 // We will create page table, just in case that SINIT does not create it.
1125 //
1126 if (MinMsegSize < StmHeader->HwStmHdr.Cr3Offset + EFI_PAGES_TO_SIZE(6)) {
1127 MinMsegSize = StmHeader->HwStmHdr.Cr3Offset + EFI_PAGES_TO_SIZE(6);
1128 }
1129 }
1130
1131 //
1132 // Check if it exceeds MSEG size
1133 //
1134 if (MinMsegSize > mMsegSize) {
1135 DEBUG ((DEBUG_ERROR, "MSEG too small. Min MSEG Size = %08x Current MSEG Size = %08x\n", MinMsegSize, mMsegSize));
1136 DEBUG ((DEBUG_ERROR, " StmHeader->SwStmHdr.StaticImageSize = %08x\n", StmHeader->SwStmHdr.StaticImageSize));
1137 DEBUG ((DEBUG_ERROR, " StmHeader->SwStmHdr.AdditionalDynamicMemorySize = %08x\n", StmHeader->SwStmHdr.AdditionalDynamicMemorySize));
1138 DEBUG ((DEBUG_ERROR, " StmHeader->SwStmHdr.PerProcDynamicMemorySize = %08x\n", StmHeader->SwStmHdr.PerProcDynamicMemorySize));
1139 DEBUG ((DEBUG_ERROR, " VMCS Size = %08x\n", GetVmcsSize ()));
1140 DEBUG ((DEBUG_ERROR, " Max CPUs = %08x\n", gSmst->NumberOfCpus));
1141 DEBUG ((DEBUG_ERROR, " StmHeader->HwStmHdr.Cr3Offset = %08x\n", StmHeader->HwStmHdr.Cr3Offset));
1142 return FALSE;
1143 }
1144
1145 return TRUE;
1146 }
1147
1148 /**
1149
1150 Load STM image to MSEG.
1151
1152 @param StmImage STM image
1153 @param StmImageSize STM image size
1154
1155 **/
1156 VOID
1157 StmLoadStmImage (
1158 IN EFI_PHYSICAL_ADDRESS StmImage,
1159 IN UINTN StmImageSize
1160 )
1161 {
1162 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl;
1163 UINT32 MsegBase;
1164 STM_HEADER *StmHeader;
1165
1166 //
1167 // Get MSEG base address from MSR_IA32_SMM_MONITOR_CTL
1168 //
1169 SmmMonitorCtl.Uint64 = AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL);
1170 MsegBase = SmmMonitorCtl.Bits.MsegBase << 12;
1171
1172 //
1173 // Zero all of MSEG base address
1174 //
1175 ZeroMem ((VOID *)(UINTN)MsegBase, mMsegSize);
1176
1177 //
1178 // Copy STM Image into MSEG
1179 //
1180 CopyMem ((VOID *)(UINTN)MsegBase, (VOID *)(UINTN)StmImage, StmImageSize);
1181
1182 //
1183 // STM Header is at the beginning of the STM Image
1184 //
1185 StmHeader = (STM_HEADER *)(UINTN)StmImage;
1186
1187 StmGen4GPageTable ((UINTN)MsegBase + StmHeader->HwStmHdr.Cr3Offset);
1188 }
1189
1190 /**
1191
1192 Load STM image to MSEG.
1193
1194 @param StmImage STM image
1195 @param StmImageSize STM image size
1196
1197 @retval EFI_SUCCESS Load STM to MSEG successfully
1198 @retval EFI_ALREADY_STARTED STM image is already loaded to MSEG
1199 @retval EFI_BUFFER_TOO_SMALL MSEG is smaller than minimal requirement of STM image
1200 @retval EFI_UNSUPPORTED MSEG is not enabled
1201
1202 **/
1203 EFI_STATUS
1204 EFIAPI
1205 LoadMonitor (
1206 IN EFI_PHYSICAL_ADDRESS StmImage,
1207 IN UINTN StmImageSize
1208 )
1209 {
1210 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl;
1211
1212 if (mLockLoadMonitor) {
1213 return EFI_ACCESS_DENIED;
1214 }
1215
1216 SmmMonitorCtl.Uint64 = AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL);
1217 if (SmmMonitorCtl.Bits.MsegBase == 0) {
1218 return EFI_UNSUPPORTED;
1219 }
1220
1221 if (!StmCheckStmImage (StmImage, StmImageSize)) {
1222 return EFI_BUFFER_TOO_SMALL;
1223 }
1224
1225 // Record STM_HASH to PCR 0, just in case it is NOT TXT launch, we still need provide the evidence.
1226 TpmMeasureAndLogData(
1227 0, // PcrIndex
1228 TXT_EVTYPE_STM_HASH, // EventType
1229 NULL, // EventLog
1230 0, // LogLen
1231 (VOID *)(UINTN)StmImage, // HashData
1232 StmImageSize // HashDataLen
1233 );
1234
1235 StmLoadStmImage (StmImage, StmImageSize);
1236
1237 mStmState |= EFI_SM_MONITOR_STATE_ENABLED;
1238
1239 return EFI_SUCCESS;
1240 }
1241
1242 /**
1243 This function return BIOS STM resource.
1244 Produced by SmmStm.
1245 Comsumed by SmmMpService when Init.
1246
1247 @return BIOS STM resource
1248
1249 **/
1250 VOID *
1251 GetStmResource(
1252 VOID
1253 )
1254 {
1255 return mStmResourcesPtr;
1256 }
1257
1258 /**
1259 This function notify STM resource change.
1260
1261 @param StmResource BIOS STM resource
1262
1263 **/
1264 VOID
1265 NotifyStmResourceChange (
1266 VOID *StmResource
1267 )
1268 {
1269 UINTN Index;
1270 TXT_PROCESSOR_SMM_DESCRIPTOR *Psd;
1271
1272 for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
1273 Psd = (TXT_PROCESSOR_SMM_DESCRIPTOR *)((UINTN)gSmst->CpuSaveState[Index] - SMRAM_SAVE_STATE_MAP_OFFSET + TXT_SMM_PSD_OFFSET);
1274 Psd->BiosHwResourceRequirementsPtr = (UINT64)(UINTN)StmResource;
1275 }
1276 return ;
1277 }
1278
1279
1280 /**
1281 This is STM setup BIOS callback.
1282 **/
1283 VOID
1284 EFIAPI
1285 SmmStmSetup (
1286 VOID
1287 )
1288 {
1289 mStmState |= EFI_SM_MONITOR_STATE_ACTIVATED;
1290 }
1291
1292 /**
1293 This is STM teardown BIOS callback.
1294 **/
1295 VOID
1296 EFIAPI
1297 SmmStmTeardown (
1298 VOID
1299 )
1300 {
1301 mStmState &= ~EFI_SM_MONITOR_STATE_ACTIVATED;
1302 }
1303