StandaloneMmPkg/StandaloneMmCpu: fix typo Standlone -> Standalone
[mirror_edk2.git] / StandaloneMmPkg / Drivers / StandaloneMmCpu / AArch64 / EventHandle.c
1 /** @file\r
2 \r
3   Copyright (c) 2016 HP Development Company, L.P.\r
4   Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.\r
5 \r
6   This program and the accompanying materials\r
7   are licensed and made available under the terms and conditions of the BSD License\r
8   which accompanies this distribution.  The full text of the license may be found at\r
9   http://opensource.org/licenses/bsd-license.php\r
10 \r
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13 \r
14 **/\r
15 \r
16 #include <Base.h>\r
17 #include <Pi/PiMmCis.h>\r
18 \r
19 \r
20 #include <Library/ArmSvcLib.h>\r
21 #include <Library/ArmLib.h>\r
22 #include <Library/BaseMemoryLib.h>\r
23 #include <Library/DebugLib.h>\r
24 #include <Library/HobLib.h>\r
25 \r
26 #include <Protocol/DebugSupport.h> // for EFI_SYSTEM_CONTEXT\r
27 \r
28 #include <Guid/ZeroGuid.h>\r
29 #include <Guid/MmramMemoryReserve.h>\r
30 \r
31 #include <IndustryStandard/ArmStdSmc.h>\r
32 \r
33 #include "StandaloneMmCpu.h"\r
34 \r
35 EFI_STATUS\r
36 EFIAPI\r
37 MmFoundationEntryRegister (\r
38   IN CONST EFI_MM_CONFIGURATION_PROTOCOL  *This,\r
39   IN EFI_MM_ENTRY_POINT                    MmEntryPoint\r
40   );\r
41 \r
42 //\r
43 // On ARM platforms every event is expected to have a GUID associated with\r
44 // it. It will be used by the MM Entry point to find the handler for the\r
45 // event. It will either be populated in a EFI_MM_COMMUNICATE_HEADER by the\r
46 // caller of the event (e.g. MM_COMMUNICATE SMC) or by the CPU driver\r
47 // (e.g. during an asynchronous event). In either case, this context is\r
48 // maintained in an array which has an entry for each CPU. The pointer to this\r
49 // array is held in PerCpuGuidedEventContext. Memory is allocated once the\r
50 // number of CPUs in the system are made known through the\r
51 // MP_INFORMATION_HOB_DATA.\r
52 //\r
53 EFI_MM_COMMUNICATE_HEADER **PerCpuGuidedEventContext = NULL;\r
54 \r
55 // Descriptor with whereabouts of memory used for communication with the normal world\r
56 EFI_MMRAM_DESCRIPTOR  mNsCommBuffer;\r
57 \r
58 MP_INFORMATION_HOB_DATA *mMpInformationHobData;\r
59 \r
60 EFI_MM_CONFIGURATION_PROTOCOL mMmConfig = {\r
61   0,\r
62   MmFoundationEntryRegister\r
63 };\r
64 \r
65 STATIC EFI_MM_ENTRY_POINT     mMmEntryPoint = NULL;\r
66 \r
67 EFI_STATUS\r
68 PiMmStandaloneArmTfCpuDriverEntry (\r
69   IN UINTN EventId,\r
70   IN UINTN CpuNumber,\r
71   IN UINTN NsCommBufferAddr\r
72   )\r
73 {\r
74   EFI_MM_COMMUNICATE_HEADER *GuidedEventContext = NULL;\r
75   EFI_MM_ENTRY_CONTEXT        MmEntryPointContext = {0};\r
76   EFI_STATUS                  Status;\r
77   UINTN                       NsCommBufferSize;\r
78 \r
79   DEBUG ((DEBUG_INFO, "Received event - 0x%x on cpu %d\n", EventId, CpuNumber));\r
80 \r
81   Status = EFI_SUCCESS;\r
82   //\r
83   // ARM TF passes SMC FID of the MM_COMMUNICATE interface as the Event ID upon\r
84   // receipt of a synchronous MM request. Use the Event ID to distinguish\r
85   // between synchronous and asynchronous events.\r
86   //\r
87   if (ARM_SMC_ID_MM_COMMUNICATE_AARCH64 != EventId) {\r
88     DEBUG ((DEBUG_INFO, "UnRecognized Event - 0x%x\n", EventId));\r
89     return EFI_INVALID_PARAMETER;\r
90   }\r
91 \r
92   // Perform parameter validation of NsCommBufferAddr\r
93   if (NsCommBufferAddr && (NsCommBufferAddr < mNsCommBuffer.PhysicalStart))\r
94     return EFI_ACCESS_DENIED;\r
95 \r
96   if ((NsCommBufferAddr + sizeof (EFI_MM_COMMUNICATE_HEADER)) >=\r
97       (mNsCommBuffer.PhysicalStart + mNsCommBuffer.PhysicalSize))\r
98     return EFI_INVALID_PARAMETER;\r
99 \r
100   // Find out the size of the buffer passed\r
101   NsCommBufferSize = ((EFI_MM_COMMUNICATE_HEADER *) NsCommBufferAddr)->MessageLength +\r
102     sizeof (EFI_MM_COMMUNICATE_HEADER);\r
103 \r
104   // perform bounds check.\r
105   if (NsCommBufferAddr + NsCommBufferSize >=\r
106       mNsCommBuffer.PhysicalStart + mNsCommBuffer.PhysicalSize)\r
107     return EFI_ACCESS_DENIED;\r
108 \r
109 \r
110   // Now that the secure world can see the normal world buffer, allocate\r
111   // memory to copy the communication buffer to the secure world.\r
112   Status = mMmst->MmAllocatePool (\r
113                     EfiRuntimeServicesData,\r
114                     NsCommBufferSize,\r
115                     (VOID **) &GuidedEventContext\r
116                     );\r
117 \r
118   if (Status != EFI_SUCCESS) {\r
119     DEBUG ((DEBUG_INFO, "Mem alloc failed - 0x%x\n", EventId));\r
120     return EFI_OUT_OF_RESOURCES;\r
121   }\r
122 \r
123   // X1 contains the VA of the normal world memory accessible from\r
124   // S-EL0\r
125   CopyMem (GuidedEventContext, (CONST VOID *) NsCommBufferAddr, NsCommBufferSize);\r
126 \r
127   // Stash the pointer to the allocated Event Context for this CPU\r
128   PerCpuGuidedEventContext[CpuNumber] = GuidedEventContext;\r
129 \r
130   MmEntryPointContext.CurrentlyExecutingCpu = CpuNumber;\r
131   MmEntryPointContext.NumberOfCpus = mMpInformationHobData->NumberOfProcessors;\r
132 \r
133   // Populate the MM system table with MP and state information\r
134   mMmst->CurrentlyExecutingCpu = CpuNumber;\r
135   mMmst->NumberOfCpus = mMpInformationHobData->NumberOfProcessors;\r
136   mMmst->CpuSaveStateSize = 0;\r
137   mMmst->CpuSaveState = NULL;\r
138 \r
139   if (mMmEntryPoint == NULL) {\r
140     DEBUG ((DEBUG_INFO, "Mm Entry point Not Found\n"));\r
141     return EFI_UNSUPPORTED;\r
142   }\r
143 \r
144   mMmEntryPoint (&MmEntryPointContext);\r
145 \r
146   // Free the memory allocation done earlier and reset the per-cpu context\r
147   ASSERT (GuidedEventContext);\r
148   CopyMem ((VOID *)NsCommBufferAddr, (CONST VOID *) GuidedEventContext, NsCommBufferSize);\r
149 \r
150   Status = mMmst->MmFreePool ((VOID *) GuidedEventContext);\r
151   if (Status != EFI_SUCCESS) {\r
152     return EFI_OUT_OF_RESOURCES;\r
153   }\r
154   PerCpuGuidedEventContext[CpuNumber] = NULL;\r
155 \r
156   return Status;\r
157 }\r
158 \r
159 EFI_STATUS\r
160 EFIAPI\r
161 MmFoundationEntryRegister (\r
162   IN CONST EFI_MM_CONFIGURATION_PROTOCOL  *This,\r
163   IN EFI_MM_ENTRY_POINT                    MmEntryPoint\r
164   )\r
165 {\r
166   // store the entry point in a global\r
167   mMmEntryPoint = MmEntryPoint;\r
168   return EFI_SUCCESS;\r
169 }\r
170 \r
171 /**\r
172   This function is the main entry point for an MM handler dispatch\r
173   or communicate-based callback.\r
174 \r
175   @param  DispatchHandle  The unique handle assigned to this handler by MmiHandlerRegister().\r
176   @param  Context         Points to an optional handler context which was specified when the handler was registered.\r
177   @param  CommBuffer      A pointer to a collection of data in memory that will\r
178                           be conveyed from a non-MM environment into an MM environment.\r
179   @param  CommBufferSize  The size of the CommBuffer.\r
180 \r
181   @return Status Code\r
182 \r
183 **/\r
184 EFI_STATUS\r
185 EFIAPI\r
186 PiMmCpuTpFwRootMmiHandler (\r
187   IN     EFI_HANDLE               DispatchHandle,\r
188   IN     CONST VOID               *Context,        OPTIONAL\r
189   IN OUT VOID                     *CommBuffer,     OPTIONAL\r
190   IN OUT UINTN                    *CommBufferSize  OPTIONAL\r
191   )\r
192 {\r
193   EFI_STATUS Status;\r
194   UINTN      CpuNumber;\r
195 \r
196   ASSERT (Context == NULL);\r
197   ASSERT (CommBuffer == NULL);\r
198   ASSERT (CommBufferSize == NULL);\r
199 \r
200   CpuNumber = mMmst->CurrentlyExecutingCpu;\r
201   if (!PerCpuGuidedEventContext[CpuNumber])\r
202     return EFI_NOT_FOUND;\r
203 \r
204   DEBUG ((DEBUG_INFO, "CommBuffer - 0x%x, CommBufferSize - 0x%x\n",\r
205           PerCpuGuidedEventContext[CpuNumber],\r
206           PerCpuGuidedEventContext[CpuNumber]->MessageLength));\r
207 \r
208   Status = mMmst->MmiManage (\r
209                     &PerCpuGuidedEventContext[CpuNumber]->HeaderGuid,\r
210                     NULL,\r
211                     PerCpuGuidedEventContext[CpuNumber]->Data,\r
212                     &PerCpuGuidedEventContext[CpuNumber]->MessageLength\r
213                     );\r
214 \r
215   if (Status != EFI_SUCCESS) {\r
216     DEBUG ((DEBUG_WARN, "Unable to manage Guided Event - %d\n", Status));\r
217   }\r
218 \r
219   return Status;\r
220 }\r