]>
Commit | Line | Data |
---|---|---|
b6490426 BB |
1 | /** @file -- VariablePolicySmmDxe.c\r |
2 | This protocol allows communication with Variable Policy Engine.\r | |
3 | \r | |
4 | Copyright (c) Microsoft Corporation.\r | |
5 | SPDX-License-Identifier: BSD-2-Clause-Patent\r | |
6 | \r | |
7 | **/\r | |
8 | \r | |
9 | #include <Library/BaseLib.h>\r | |
10 | #include <Library/UefiLib.h>\r | |
11 | #include <Library/DebugLib.h>\r | |
12 | #include <Library/SafeIntLib.h>\r | |
13 | #include <Library/UefiBootServicesTableLib.h>\r | |
14 | #include <Library/BaseMemoryLib.h>\r | |
15 | #include <Library/MemoryAllocationLib.h>\r | |
16 | \r | |
17 | #include <Protocol/VariablePolicy.h>\r | |
18 | #include <Protocol/MmCommunication2.h>\r | |
19 | \r | |
20 | #include <Guid/VarCheckPolicyMmi.h>\r | |
21 | \r | |
22 | #include "Variable.h"\r | |
23 | \r | |
24 | EDKII_VARIABLE_POLICY_PROTOCOL mVariablePolicyProtocol;\r | |
25 | EFI_MM_COMMUNICATION2_PROTOCOL *mMmCommunication;\r | |
26 | \r | |
27 | VOID *mMmCommunicationBuffer;\r | |
28 | UINTN mMmCommunicationBufferSize;\r | |
29 | EFI_LOCK mMmCommunicationLock;\r | |
30 | \r | |
31 | /**\r | |
32 | Internal helper function to consolidate communication method.\r | |
33 | \r | |
34 | @param[in,out] CommBuffer\r | |
35 | @param[in,out] CommSize Size of the CommBuffer.\r | |
36 | \r | |
37 | @retval EFI_STATUS Result from communication method.\r | |
38 | \r | |
39 | **/\r | |
40 | STATIC\r | |
41 | EFI_STATUS\r | |
42 | InternalMmCommunicate (\r | |
1436aea4 MK |
43 | IN OUT VOID *CommBuffer,\r |
44 | IN OUT UINTN *CommSize\r | |
b6490426 BB |
45 | )\r |
46 | {\r | |
1436aea4 MK |
47 | EFI_STATUS Status;\r |
48 | \r | |
49 | if ((CommBuffer == NULL) || (CommSize == NULL)) {\r | |
b6490426 BB |
50 | return EFI_INVALID_PARAMETER;\r |
51 | }\r | |
1436aea4 | 52 | \r |
b6490426 BB |
53 | Status = mMmCommunication->Communicate (mMmCommunication, CommBuffer, CommBuffer, CommSize);\r |
54 | return Status;\r | |
55 | }\r | |
56 | \r | |
b6490426 BB |
57 | /**\r |
58 | This API function disables the variable policy enforcement. If it's\r | |
59 | already been called once, will return EFI_ALREADY_STARTED.\r | |
60 | \r | |
61 | @retval EFI_SUCCESS\r | |
62 | @retval EFI_ALREADY_STARTED Has already been called once this boot.\r | |
63 | @retval EFI_WRITE_PROTECTED Interface has been locked until reboot.\r | |
64 | @retval EFI_WRITE_PROTECTED Interface option is disabled by platform PCD.\r | |
65 | \r | |
66 | **/\r | |
67 | STATIC\r | |
68 | EFI_STATUS\r | |
69 | EFIAPI\r | |
70 | ProtocolDisableVariablePolicy (\r | |
71 | VOID\r | |
72 | )\r | |
73 | {\r | |
74 | EFI_STATUS Status;\r | |
75 | EFI_MM_COMMUNICATE_HEADER *CommHeader;\r | |
76 | VAR_CHECK_POLICY_COMM_HEADER *PolicyHeader;\r | |
77 | UINTN BufferSize;\r | |
78 | \r | |
79 | // Check the PCD for convenience.\r | |
80 | // This would also be rejected by the lib, but why go to MM if we don't have to?\r | |
81 | if (!PcdGetBool (PcdAllowVariablePolicyEnforcementDisable)) {\r | |
82 | return EFI_WRITE_PROTECTED;\r | |
83 | }\r | |
84 | \r | |
85 | AcquireLockOnlyAtBootTime (&mMmCommunicationLock);\r | |
86 | \r | |
87 | // Set up the MM communication.\r | |
1436aea4 MK |
88 | BufferSize = mMmCommunicationBufferSize;\r |
89 | CommHeader = mMmCommunicationBuffer;\r | |
90 | PolicyHeader = (VAR_CHECK_POLICY_COMM_HEADER *)&CommHeader->Data;\r | |
91 | CopyGuid (&CommHeader->HeaderGuid, &gVarCheckPolicyLibMmiHandlerGuid);\r | |
ee67067f | 92 | CommHeader->MessageLength = BufferSize - OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data);\r |
b6490426 BB |
93 | PolicyHeader->Signature = VAR_CHECK_POLICY_COMM_SIG;\r |
94 | PolicyHeader->Revision = VAR_CHECK_POLICY_COMM_REVISION;\r | |
95 | PolicyHeader->Command = VAR_CHECK_POLICY_COMMAND_DISABLE;\r | |
96 | \r | |
97 | Status = InternalMmCommunicate (CommHeader, &BufferSize);\r | |
1436aea4 | 98 | DEBUG ((DEBUG_VERBOSE, "%a - MmCommunication returned %r.\n", __FUNCTION__, Status));\r |
b6490426 BB |
99 | \r |
100 | ReleaseLockOnlyAtBootTime (&mMmCommunicationLock);\r | |
101 | \r | |
1436aea4 | 102 | return (EFI_ERROR (Status)) ? Status : PolicyHeader->Result;\r |
b6490426 BB |
103 | }\r |
104 | \r | |
b6490426 BB |
105 | /**\r |
106 | This API function returns whether or not the policy engine is\r | |
107 | currently being enforced.\r | |
108 | \r | |
109 | @param[out] State Pointer to a return value for whether the policy enforcement\r | |
110 | is currently enabled.\r | |
111 | \r | |
112 | @retval EFI_SUCCESS\r | |
113 | @retval Others An error has prevented this command from completing.\r | |
114 | \r | |
115 | **/\r | |
116 | STATIC\r | |
117 | EFI_STATUS\r | |
118 | EFIAPI\r | |
119 | ProtocolIsVariablePolicyEnabled (\r | |
1436aea4 | 120 | OUT BOOLEAN *State\r |
b6490426 BB |
121 | )\r |
122 | {\r | |
1436aea4 MK |
123 | EFI_STATUS Status;\r |
124 | EFI_MM_COMMUNICATE_HEADER *CommHeader;\r | |
125 | VAR_CHECK_POLICY_COMM_HEADER *PolicyHeader;\r | |
126 | VAR_CHECK_POLICY_COMM_IS_ENABLED_PARAMS *CommandParams;\r | |
127 | UINTN BufferSize;\r | |
b6490426 BB |
128 | \r |
129 | if (State == NULL) {\r | |
130 | return EFI_INVALID_PARAMETER;\r | |
131 | }\r | |
132 | \r | |
133 | AcquireLockOnlyAtBootTime (&mMmCommunicationLock);\r | |
134 | \r | |
135 | // Set up the MM communication.\r | |
136 | BufferSize = mMmCommunicationBufferSize;\r | |
137 | CommHeader = mMmCommunicationBuffer;\r | |
1436aea4 MK |
138 | PolicyHeader = (VAR_CHECK_POLICY_COMM_HEADER *)&CommHeader->Data;\r |
139 | CommandParams = (VAR_CHECK_POLICY_COMM_IS_ENABLED_PARAMS *)(PolicyHeader + 1);\r | |
140 | CopyGuid (&CommHeader->HeaderGuid, &gVarCheckPolicyLibMmiHandlerGuid);\r | |
ee67067f | 141 | CommHeader->MessageLength = BufferSize - OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data);\r |
b6490426 BB |
142 | PolicyHeader->Signature = VAR_CHECK_POLICY_COMM_SIG;\r |
143 | PolicyHeader->Revision = VAR_CHECK_POLICY_COMM_REVISION;\r | |
144 | PolicyHeader->Command = VAR_CHECK_POLICY_COMMAND_IS_ENABLED;\r | |
145 | \r | |
146 | Status = InternalMmCommunicate (CommHeader, &BufferSize);\r | |
1436aea4 | 147 | DEBUG ((DEBUG_VERBOSE, "%a - MmCommunication returned %r.\n", __FUNCTION__, Status));\r |
b6490426 | 148 | \r |
1436aea4 | 149 | if (!EFI_ERROR (Status)) {\r |
b6490426 BB |
150 | Status = PolicyHeader->Result;\r |
151 | *State = CommandParams->State;\r | |
152 | }\r | |
153 | \r | |
154 | ReleaseLockOnlyAtBootTime (&mMmCommunicationLock);\r | |
155 | \r | |
156 | return Status;\r | |
157 | }\r | |
158 | \r | |
b6490426 BB |
159 | /**\r |
160 | This API function validates and registers a new policy with\r | |
161 | the policy enforcement engine.\r | |
162 | \r | |
163 | @param[in] NewPolicy Pointer to the incoming policy structure.\r | |
164 | \r | |
165 | @retval EFI_SUCCESS\r | |
166 | @retval EFI_INVALID_PARAMETER NewPolicy is NULL or is internally inconsistent.\r | |
167 | @retval EFI_ALREADY_STARTED An identical matching policy already exists.\r | |
168 | @retval EFI_WRITE_PROTECTED The interface has been locked until the next reboot.\r | |
169 | @retval EFI_UNSUPPORTED Policy enforcement has been disabled. No reason to add more policies.\r | |
170 | @retval EFI_ABORTED A calculation error has prevented this function from completing.\r | |
171 | @retval EFI_OUT_OF_RESOURCES Cannot grow the table to hold any more policies.\r | |
172 | \r | |
173 | **/\r | |
174 | STATIC\r | |
175 | EFI_STATUS\r | |
176 | EFIAPI\r | |
177 | ProtocolRegisterVariablePolicy (\r | |
1436aea4 | 178 | IN CONST VARIABLE_POLICY_ENTRY *NewPolicy\r |
b6490426 BB |
179 | )\r |
180 | {\r | |
1436aea4 MK |
181 | EFI_STATUS Status;\r |
182 | EFI_MM_COMMUNICATE_HEADER *CommHeader;\r | |
183 | VAR_CHECK_POLICY_COMM_HEADER *PolicyHeader;\r | |
184 | VOID *PolicyBuffer;\r | |
185 | UINTN BufferSize;\r | |
186 | UINTN RequiredSize;\r | |
b6490426 BB |
187 | \r |
188 | if (NewPolicy == NULL) {\r | |
189 | return EFI_INVALID_PARAMETER;\r | |
190 | }\r | |
191 | \r | |
192 | // First, make sure that the required size does not exceed the capabilities\r | |
193 | // of the MmCommunication buffer.\r | |
1436aea4 MK |
194 | RequiredSize = OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data) + sizeof (VAR_CHECK_POLICY_COMM_HEADER);\r |
195 | Status = SafeUintnAdd (RequiredSize, NewPolicy->Size, &RequiredSize);\r | |
196 | if (EFI_ERROR (Status) || (RequiredSize > mMmCommunicationBufferSize)) {\r | |
197 | DEBUG ((\r | |
198 | DEBUG_ERROR,\r | |
199 | "%a - Policy too large for buffer! %r, %d > %d \n",\r | |
200 | __FUNCTION__,\r | |
201 | Status,\r | |
202 | RequiredSize,\r | |
203 | mMmCommunicationBufferSize\r | |
204 | ));\r | |
b6490426 BB |
205 | return EFI_OUT_OF_RESOURCES;\r |
206 | }\r | |
207 | \r | |
208 | AcquireLockOnlyAtBootTime (&mMmCommunicationLock);\r | |
209 | \r | |
210 | // Set up the MM communication.\r | |
1436aea4 MK |
211 | BufferSize = mMmCommunicationBufferSize;\r |
212 | CommHeader = mMmCommunicationBuffer;\r | |
213 | PolicyHeader = (VAR_CHECK_POLICY_COMM_HEADER *)&CommHeader->Data;\r | |
214 | PolicyBuffer = (VOID *)(PolicyHeader + 1);\r | |
215 | CopyGuid (&CommHeader->HeaderGuid, &gVarCheckPolicyLibMmiHandlerGuid);\r | |
ee67067f | 216 | CommHeader->MessageLength = BufferSize - OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data);\r |
b6490426 BB |
217 | PolicyHeader->Signature = VAR_CHECK_POLICY_COMM_SIG;\r |
218 | PolicyHeader->Revision = VAR_CHECK_POLICY_COMM_REVISION;\r | |
219 | PolicyHeader->Command = VAR_CHECK_POLICY_COMMAND_REGISTER;\r | |
220 | \r | |
221 | // Copy the policy into place. This copy is safe because we've already tested above.\r | |
1436aea4 | 222 | CopyMem (PolicyBuffer, NewPolicy, NewPolicy->Size);\r |
b6490426 BB |
223 | \r |
224 | Status = InternalMmCommunicate (CommHeader, &BufferSize);\r | |
1436aea4 | 225 | DEBUG ((DEBUG_VERBOSE, "%a - MmCommunication returned %r.\n", __FUNCTION__, Status));\r |
b6490426 BB |
226 | \r |
227 | ReleaseLockOnlyAtBootTime (&mMmCommunicationLock);\r | |
228 | \r | |
1436aea4 | 229 | return (EFI_ERROR (Status)) ? Status : PolicyHeader->Result;\r |
b6490426 BB |
230 | }\r |
231 | \r | |
b6490426 BB |
232 | /**\r |
233 | This helper function takes care of the overhead of formatting, sending, and interpreting\r | |
234 | the results for a single DumpVariablePolicy request.\r | |
235 | \r | |
236 | @param[in] PageRequested The page of the paginated results from MM. 0 for metadata.\r | |
237 | @param[out] TotalSize The total size of the entire buffer. Returned as part of metadata.\r | |
238 | @param[out] PageSize The size of the current page being returned. Not valid as part of metadata.\r | |
239 | @param[out] HasMore A flag indicating whether there are more pages after this one.\r | |
240 | @param[out] Buffer The start of the current page from MM.\r | |
241 | \r | |
242 | @retval EFI_SUCCESS Output params have been updated (either metadata or dump page).\r | |
243 | @retval EFI_INVALID_PARAMETER One of the output params is NULL.\r | |
244 | @retval Others Response from MM handler.\r | |
245 | \r | |
246 | **/\r | |
247 | STATIC\r | |
248 | EFI_STATUS\r | |
249 | DumpVariablePolicyHelper (\r | |
1436aea4 MK |
250 | IN UINT32 PageRequested,\r |
251 | OUT UINT32 *TotalSize,\r | |
252 | OUT UINT32 *PageSize,\r | |
253 | OUT BOOLEAN *HasMore,\r | |
254 | OUT UINT8 **Buffer\r | |
b6490426 BB |
255 | )\r |
256 | {\r | |
1436aea4 MK |
257 | EFI_STATUS Status;\r |
258 | EFI_MM_COMMUNICATE_HEADER *CommHeader;\r | |
259 | VAR_CHECK_POLICY_COMM_HEADER *PolicyHeader;\r | |
260 | VAR_CHECK_POLICY_COMM_DUMP_PARAMS *CommandParams;\r | |
261 | UINTN BufferSize;\r | |
b6490426 | 262 | \r |
1436aea4 | 263 | if ((TotalSize == NULL) || (PageSize == NULL) || (HasMore == NULL) || (Buffer == NULL)) {\r |
b6490426 BB |
264 | return EFI_INVALID_PARAMETER;\r |
265 | }\r | |
266 | \r | |
267 | // Set up the MM communication.\r | |
268 | BufferSize = mMmCommunicationBufferSize;\r | |
269 | CommHeader = mMmCommunicationBuffer;\r | |
1436aea4 MK |
270 | PolicyHeader = (VAR_CHECK_POLICY_COMM_HEADER *)&CommHeader->Data;\r |
271 | CommandParams = (VAR_CHECK_POLICY_COMM_DUMP_PARAMS *)(PolicyHeader + 1);\r | |
272 | CopyGuid (&CommHeader->HeaderGuid, &gVarCheckPolicyLibMmiHandlerGuid);\r | |
ee67067f | 273 | CommHeader->MessageLength = BufferSize - OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data);\r |
b6490426 BB |
274 | PolicyHeader->Signature = VAR_CHECK_POLICY_COMM_SIG;\r |
275 | PolicyHeader->Revision = VAR_CHECK_POLICY_COMM_REVISION;\r | |
276 | PolicyHeader->Command = VAR_CHECK_POLICY_COMMAND_DUMP;\r | |
277 | \r | |
278 | CommandParams->PageRequested = PageRequested;\r | |
279 | \r | |
280 | Status = InternalMmCommunicate (CommHeader, &BufferSize);\r | |
1436aea4 | 281 | DEBUG ((DEBUG_VERBOSE, "%a - MmCommunication returned %r.\n", __FUNCTION__, Status));\r |
b6490426 | 282 | \r |
1436aea4 MK |
283 | if (!EFI_ERROR (Status)) {\r |
284 | Status = PolicyHeader->Result;\r | |
b6490426 | 285 | *TotalSize = CommandParams->TotalSize;\r |
1436aea4 MK |
286 | *PageSize = CommandParams->PageSize;\r |
287 | *HasMore = CommandParams->HasMore;\r | |
288 | *Buffer = (UINT8 *)(CommandParams + 1);\r | |
b6490426 BB |
289 | }\r |
290 | \r | |
291 | return Status;\r | |
292 | }\r | |
293 | \r | |
b6490426 BB |
294 | /**\r |
295 | This API function will dump the entire contents of the variable policy table.\r | |
296 | \r | |
297 | Similar to GetVariable, the first call can be made with a 0 size and it will return\r | |
298 | the size of the buffer required to hold the entire table.\r | |
299 | \r | |
300 | @param[out] Policy Pointer to the policy buffer. Can be NULL if Size is 0.\r | |
301 | @param[in,out] Size On input, the size of the output buffer. On output, the size\r | |
302 | of the data returned.\r | |
303 | \r | |
304 | @retval EFI_SUCCESS Policy data is in the output buffer and Size has been updated.\r | |
305 | @retval EFI_INVALID_PARAMETER Size is NULL, or Size is non-zero and Policy is NULL.\r | |
306 | @retval EFI_BUFFER_TOO_SMALL Size is insufficient to hold policy. Size updated with required size.\r | |
307 | \r | |
308 | **/\r | |
309 | STATIC\r | |
310 | EFI_STATUS\r | |
311 | EFIAPI\r | |
312 | ProtocolDumpVariablePolicy (\r | |
1436aea4 MK |
313 | OUT UINT8 *Policy OPTIONAL,\r |
314 | IN OUT UINT32 *Size\r | |
b6490426 BB |
315 | )\r |
316 | {\r | |
1436aea4 MK |
317 | EFI_STATUS Status;\r |
318 | UINT8 *Source;\r | |
319 | UINT8 *Destination;\r | |
320 | UINT32 PolicySize;\r | |
321 | UINT32 PageSize;\r | |
322 | BOOLEAN HasMore;\r | |
323 | UINT32 PageIndex;\r | |
324 | \r | |
325 | if ((Size == NULL) || ((*Size > 0) && (Policy == NULL))) {\r | |
b6490426 BB |
326 | return EFI_INVALID_PARAMETER;\r |
327 | }\r | |
328 | \r | |
329 | AcquireLockOnlyAtBootTime (&mMmCommunicationLock);\r | |
330 | \r | |
331 | // Repeat this whole process until we either have a failure case or get the entire buffer.\r | |
332 | do {\r | |
333 | // First, we must check the zero page to determine the buffer size and\r | |
334 | // reset the internal state.\r | |
335 | PolicySize = 0;\r | |
1436aea4 MK |
336 | PageSize = 0;\r |
337 | HasMore = FALSE;\r | |
338 | Status = DumpVariablePolicyHelper (0, &PolicySize, &PageSize, &HasMore, &Source);\r | |
b6490426 BB |
339 | if (EFI_ERROR (Status)) {\r |
340 | break;\r | |
341 | }\r | |
342 | \r | |
343 | // If we're good, we can at least check the required size now.\r | |
344 | if (*Size < PolicySize) {\r | |
1436aea4 | 345 | *Size = PolicySize;\r |
b6490426 BB |
346 | Status = EFI_BUFFER_TOO_SMALL;\r |
347 | break;\r | |
348 | }\r | |
349 | \r | |
350 | // On further thought, let's update the size either way.\r | |
351 | *Size = PolicySize;\r | |
352 | // And get ready to ROCK.\r | |
353 | Destination = Policy;\r | |
354 | \r | |
355 | // Keep looping and copying until we're either done or freak out.\r | |
356 | for (PageIndex = 1; !EFI_ERROR (Status) && HasMore && PageIndex < MAX_UINT32; PageIndex++) {\r | |
357 | Status = DumpVariablePolicyHelper (PageIndex, &PolicySize, &PageSize, &HasMore, &Source);\r | |
358 | if (!EFI_ERROR (Status)) {\r | |
359 | CopyMem (Destination, Source, PageSize);\r | |
360 | Destination += PageSize;\r | |
361 | }\r | |
362 | }\r | |
363 | \r | |
364 | // Next, we check to see whether\r | |
365 | } while (Status == EFI_TIMEOUT);\r | |
366 | \r | |
367 | ReleaseLockOnlyAtBootTime (&mMmCommunicationLock);\r | |
368 | \r | |
369 | // There's currently no use for this, but it shouldn't be hard to implement.\r | |
370 | return Status;\r | |
371 | }\r | |
372 | \r | |
b6490426 BB |
373 | /**\r |
374 | This API function locks the interface so that no more policy updates\r | |
375 | can be performed or changes made to the enforcement until the next boot.\r | |
376 | \r | |
377 | @retval EFI_SUCCESS\r | |
378 | @retval Others An error has prevented this command from completing.\r | |
379 | \r | |
380 | **/\r | |
381 | STATIC\r | |
382 | EFI_STATUS\r | |
383 | EFIAPI\r | |
384 | ProtocolLockVariablePolicy (\r | |
385 | VOID\r | |
386 | )\r | |
387 | {\r | |
388 | EFI_STATUS Status;\r | |
389 | EFI_MM_COMMUNICATE_HEADER *CommHeader;\r | |
390 | VAR_CHECK_POLICY_COMM_HEADER *PolicyHeader;\r | |
391 | UINTN BufferSize;\r | |
392 | \r | |
393 | AcquireLockOnlyAtBootTime (&mMmCommunicationLock);\r | |
394 | \r | |
395 | // Set up the MM communication.\r | |
1436aea4 MK |
396 | BufferSize = mMmCommunicationBufferSize;\r |
397 | CommHeader = mMmCommunicationBuffer;\r | |
398 | PolicyHeader = (VAR_CHECK_POLICY_COMM_HEADER *)&CommHeader->Data;\r | |
399 | CopyGuid (&CommHeader->HeaderGuid, &gVarCheckPolicyLibMmiHandlerGuid);\r | |
ee67067f | 400 | CommHeader->MessageLength = BufferSize - OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data);\r |
b6490426 BB |
401 | PolicyHeader->Signature = VAR_CHECK_POLICY_COMM_SIG;\r |
402 | PolicyHeader->Revision = VAR_CHECK_POLICY_COMM_REVISION;\r | |
403 | PolicyHeader->Command = VAR_CHECK_POLICY_COMMAND_LOCK;\r | |
404 | \r | |
405 | Status = InternalMmCommunicate (CommHeader, &BufferSize);\r | |
1436aea4 | 406 | DEBUG ((DEBUG_VERBOSE, "%a - MmCommunication returned %r.\n", __FUNCTION__, Status));\r |
b6490426 BB |
407 | \r |
408 | ReleaseLockOnlyAtBootTime (&mMmCommunicationLock);\r | |
409 | \r | |
1436aea4 | 410 | return (EFI_ERROR (Status)) ? Status : PolicyHeader->Result;\r |
b6490426 BB |
411 | }\r |
412 | \r | |
b6490426 BB |
413 | /**\r |
414 | This helper function locates the shared comm buffer and assigns it to input pointers.\r | |
415 | \r | |
416 | @param[in,out] BufferSize On input, the minimum buffer size required INCLUDING the MM communicate header.\r | |
417 | On output, the size of the matching buffer found.\r | |
418 | @param[out] LocatedBuffer A pointer to the matching buffer.\r | |
419 | \r | |
420 | @retval EFI_SUCCESS\r | |
421 | @retval EFI_INVALID_PARAMETER One of the output pointers was NULL.\r | |
422 | @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate a comm buffer.\r | |
423 | \r | |
424 | **/\r | |
425 | STATIC\r | |
426 | EFI_STATUS\r | |
427 | InitMmCommonCommBuffer (\r | |
1436aea4 MK |
428 | IN OUT UINTN *BufferSize,\r |
429 | OUT VOID **LocatedBuffer\r | |
b6490426 BB |
430 | )\r |
431 | {\r | |
1436aea4 | 432 | EFI_STATUS Status;\r |
b6490426 BB |
433 | \r |
434 | Status = EFI_SUCCESS;\r | |
435 | \r | |
436 | // Make sure that we're working with good pointers.\r | |
1436aea4 | 437 | if ((BufferSize == NULL) || (LocatedBuffer == NULL)) {\r |
b6490426 BB |
438 | return EFI_INVALID_PARAMETER;\r |
439 | }\r | |
440 | \r | |
441 | // Allocate the runtime memory for the comm buffer.\r | |
442 | *LocatedBuffer = AllocateRuntimePool (*BufferSize);\r | |
443 | if (*LocatedBuffer == NULL) {\r | |
1436aea4 | 444 | Status = EFI_OUT_OF_RESOURCES;\r |
b6490426 BB |
445 | *BufferSize = 0;\r |
446 | }\r | |
447 | \r | |
448 | EfiInitializeLock (&mMmCommunicationLock, TPL_NOTIFY);\r | |
449 | \r | |
450 | return Status;\r | |
451 | }\r | |
452 | \r | |
b6490426 BB |
453 | /**\r |
454 | Convert internal pointer addresses to virtual addresses.\r | |
455 | \r | |
456 | @param[in] Event Event whose notification function is being invoked.\r | |
457 | @param[in] Context The pointer to the notification function's context, which\r | |
458 | is implementation-dependent.\r | |
459 | **/\r | |
460 | STATIC\r | |
461 | VOID\r | |
462 | EFIAPI\r | |
463 | VariablePolicyVirtualAddressCallback (\r | |
1436aea4 MK |
464 | IN EFI_EVENT Event,\r |
465 | IN VOID *Context\r | |
b6490426 BB |
466 | )\r |
467 | {\r | |
468 | EfiConvertPointer (0, (VOID **)&mMmCommunication);\r | |
469 | EfiConvertPointer (0, (VOID **)&mMmCommunicationBuffer);\r | |
470 | }\r | |
471 | \r | |
b6490426 BB |
472 | /**\r |
473 | The driver's entry point.\r | |
474 | \r | |
475 | @param[in] ImageHandle The firmware allocated handle for the EFI image.\r | |
476 | @param[in] SystemTable A pointer to the EFI System Table.\r | |
477 | \r | |
478 | @retval EFI_SUCCESS The entry point executed successfully.\r | |
479 | @retval other Some error occured when executing this entry point.\r | |
480 | \r | |
481 | **/\r | |
482 | EFI_STATUS\r | |
483 | EFIAPI\r | |
484 | VariablePolicySmmDxeMain (\r | |
1436aea4 MK |
485 | IN EFI_HANDLE ImageHandle,\r |
486 | IN EFI_SYSTEM_TABLE *SystemTable\r | |
b6490426 BB |
487 | )\r |
488 | {\r | |
1436aea4 MK |
489 | EFI_STATUS Status;\r |
490 | BOOLEAN ProtocolInstalled;\r | |
491 | BOOLEAN VirtualAddressChangeRegistered;\r | |
492 | EFI_EVENT VirtualAddressChangeEvent;\r | |
b6490426 | 493 | \r |
1436aea4 MK |
494 | Status = EFI_SUCCESS;\r |
495 | ProtocolInstalled = FALSE;\r | |
b6490426 BB |
496 | VirtualAddressChangeRegistered = FALSE;\r |
497 | \r | |
498 | // Update the minimum buffer size.\r | |
499 | mMmCommunicationBufferSize = VAR_CHECK_POLICY_MM_COMM_BUFFER_SIZE;\r | |
500 | // Locate the shared comm buffer to use for sending MM commands.\r | |
1436aea4 MK |
501 | Status = InitMmCommonCommBuffer (&mMmCommunicationBufferSize, &mMmCommunicationBuffer);\r |
502 | if (EFI_ERROR (Status)) {\r | |
503 | DEBUG ((DEBUG_ERROR, "%a - Failed to locate a viable MM comm buffer! %r\n", __FUNCTION__, Status));\r | |
504 | ASSERT_EFI_ERROR (Status);\r | |
b6490426 BB |
505 | return Status;\r |
506 | }\r | |
507 | \r | |
508 | // Locate the MmCommunication protocol.\r | |
1436aea4 MK |
509 | Status = gBS->LocateProtocol (&gEfiMmCommunication2ProtocolGuid, NULL, (VOID **)&mMmCommunication);\r |
510 | if (EFI_ERROR (Status)) {\r | |
511 | DEBUG ((DEBUG_ERROR, "%a - Failed to locate MmCommunication protocol! %r\n", __FUNCTION__, Status));\r | |
512 | ASSERT_EFI_ERROR (Status);\r | |
b6490426 BB |
513 | return Status;\r |
514 | }\r | |
515 | \r | |
516 | // Configure the VariablePolicy protocol structure.\r | |
517 | mVariablePolicyProtocol.Revision = EDKII_VARIABLE_POLICY_PROTOCOL_REVISION;\r | |
518 | mVariablePolicyProtocol.DisableVariablePolicy = ProtocolDisableVariablePolicy;\r | |
519 | mVariablePolicyProtocol.IsVariablePolicyEnabled = ProtocolIsVariablePolicyEnabled;\r | |
520 | mVariablePolicyProtocol.RegisterVariablePolicy = ProtocolRegisterVariablePolicy;\r | |
521 | mVariablePolicyProtocol.DumpVariablePolicy = ProtocolDumpVariablePolicy;\r | |
522 | mVariablePolicyProtocol.LockVariablePolicy = ProtocolLockVariablePolicy;\r | |
523 | \r | |
524 | // Register all the protocols and return the status.\r | |
1436aea4 MK |
525 | Status = gBS->InstallMultipleProtocolInterfaces (\r |
526 | &ImageHandle,\r | |
527 | &gEdkiiVariablePolicyProtocolGuid,\r | |
528 | &mVariablePolicyProtocol,\r | |
529 | NULL\r | |
530 | );\r | |
531 | if (EFI_ERROR (Status)) {\r | |
532 | DEBUG ((DEBUG_ERROR, "%a - Failed to install protocol! %r\n", __FUNCTION__, Status));\r | |
b6490426 | 533 | goto Exit;\r |
1436aea4 | 534 | } else {\r |
b6490426 BB |
535 | ProtocolInstalled = TRUE;\r |
536 | }\r | |
537 | \r | |
538 | // Normally, we might want to register a callback\r | |
539 | // to lock the interface, but this is integrated\r | |
540 | // into the existing callbacks in VaraiableSmm.c\r | |
541 | // and VariableDxe.c.\r | |
542 | \r | |
543 | //\r | |
544 | // Register a VirtualAddressChange callback for the MmComm protocol and Comm buffer.\r | |
1436aea4 MK |
545 | Status = gBS->CreateEventEx (\r |
546 | EVT_NOTIFY_SIGNAL,\r | |
547 | TPL_NOTIFY,\r | |
548 | VariablePolicyVirtualAddressCallback,\r | |
549 | NULL,\r | |
550 | &gEfiEventVirtualAddressChangeGuid,\r | |
551 | &VirtualAddressChangeEvent\r | |
552 | );\r | |
553 | if (EFI_ERROR (Status)) {\r | |
554 | DEBUG ((DEBUG_ERROR, "%a - Failed to create VirtualAddressChange event! %r\n", __FUNCTION__, Status));\r | |
b6490426 | 555 | goto Exit;\r |
1436aea4 | 556 | } else {\r |
b6490426 BB |
557 | VirtualAddressChangeRegistered = TRUE;\r |
558 | }\r | |
559 | \r | |
b6490426 BB |
560 | Exit:\r |
561 | //\r | |
562 | // If we're about to return a failed status (and unload this driver), we must first undo anything that\r | |
563 | // has been successfully done.\r | |
1436aea4 | 564 | if (EFI_ERROR (Status)) {\r |
b6490426 | 565 | if (ProtocolInstalled) {\r |
1436aea4 | 566 | gBS->UninstallProtocolInterface (&ImageHandle, &gEdkiiVariablePolicyProtocolGuid, &mVariablePolicyProtocol);\r |
b6490426 | 567 | }\r |
1436aea4 | 568 | \r |
b6490426 | 569 | if (VirtualAddressChangeRegistered) {\r |
1436aea4 | 570 | gBS->CloseEvent (VirtualAddressChangeEvent);\r |
b6490426 BB |
571 | }\r |
572 | }\r | |
573 | \r | |
574 | return Status;\r | |
575 | }\r |