VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Common/DynamicPlatRepoLib/DynamicPlatRepo.c

最後變更 在這個檔案是 105670,由 vboxsync 提交於 7 月 前

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

  • 屬性 svn:eol-style 設為 native
檔案大小: 13.5 KB
 
1/** @file
2 Dynamic Platform Info Repository
3
4 Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
5 Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 @par Glossary:
10 - Cm or CM - Configuration Manager
11 - Obj or OBJ - Object
12**/
13
14#include <Protocol/ConfigurationManagerProtocol.h>
15#include <Library/BaseLib.h>
16#include <Library/BaseMemoryLib.h>
17#include <Library/DebugLib.h>
18#include <Library/MemoryAllocationLib.h>
19
20#include "CmObjectTokenFixer.h"
21#include "DynamicPlatRepoInternal.h"
22#include "TokenGenerator.h"
23
24/** Allocate a CM_OBJ_NODE.
25
26 @param [in] CmObjDesc CmObj to wrap in a node.
27 All the fields of the CmObj (Data field included),
28 are copied.
29 @param [in] Token Token to assign to this CmObj/node.
30 @param [out] ObjNode Allocated ObjNode.
31
32 @retval EFI_SUCCESS Success.
33 @retval EFI_INVALID_PARAMETER A parameter is invalid.
34 @retval EFI_OUT_OF_RESOURCES An allocation has failed.
35**/
36STATIC
37EFI_STATUS
38EFIAPI
39AllocCmObjNode (
40 IN CONST CM_OBJ_DESCRIPTOR *CmObjDesc,
41 IN CM_OBJECT_TOKEN Token,
42 OUT CM_OBJ_NODE **ObjNode
43 )
44{
45 CM_OBJ_NODE *Node;
46 CM_OBJ_DESCRIPTOR *Desc;
47
48 if ((CmObjDesc == NULL) || (ObjNode == NULL)) {
49 ASSERT (0);
50 return EFI_INVALID_PARAMETER;
51 }
52
53 Node = AllocateZeroPool (sizeof (CM_OBJ_NODE));
54 if (Node == NULL) {
55 ASSERT (0);
56 return EFI_OUT_OF_RESOURCES;
57 }
58
59 // Initialise the list head.
60 InitializeListHead (&Node->Link);
61 Node->Token = Token;
62 Desc = &Node->CmObjDesc;
63 Desc->ObjectId = CmObjDesc->ObjectId;
64 Desc->Size = CmObjDesc->Size;
65 Desc->Count = CmObjDesc->Count;
66
67 // Allocate and copy the CmObject Data.
68 Desc->Data = AllocateCopyPool (CmObjDesc->Size, CmObjDesc->Data);
69 if (Desc->Data == NULL) {
70 FreePool (Node);
71 ASSERT (0);
72 return EFI_OUT_OF_RESOURCES;
73 }
74
75 *ObjNode = Node;
76 return EFI_SUCCESS;
77}
78
79/** Free a CM_OBJ_NODE.
80
81 @param [in] ObjNode ObjNode to free.
82
83 @retval EFI_SUCCESS Success.
84 @retval EFI_INVALID_PARAMETER A parameter is invalid.
85**/
86STATIC
87EFI_STATUS
88EFIAPI
89FreeCmObjNode (
90 IN CM_OBJ_NODE *ObjNode
91 )
92{
93 CM_OBJ_DESCRIPTOR *Desc;
94
95 if (ObjNode == NULL) {
96 ASSERT (0);
97 return EFI_INVALID_PARAMETER;
98 }
99
100 // Unlink Node
101 RemoveEntryList (&ObjNode->Link);
102
103 Desc = &ObjNode->CmObjDesc;
104 if (Desc->Data != NULL) {
105 FreePool (Desc->Data);
106 }
107
108 FreePool (ObjNode);
109 return EFI_SUCCESS;
110}
111
112/** Add an object to the dynamic platform repository.
113
114 @param [in] This This dynamic platform repository.
115 @param [in] CmObjDesc CmObj to add. The data is copied.
116 @param [out] Token If not NULL, token allocated to this CmObj.
117
118 @retval EFI_SUCCESS Success.
119 @retval EFI_INVALID_PARAMETER A parameter is invalid.
120 @retval EFI_OUT_OF_RESOURCES An allocation has failed.
121**/
122EFI_STATUS
123EFIAPI
124DynPlatRepoAddObject (
125 IN DYNAMIC_PLATFORM_REPOSITORY_INFO *This,
126 IN CONST CM_OBJ_DESCRIPTOR *CmObjDesc,
127 OUT CM_OBJECT_TOKEN *Token OPTIONAL
128 )
129{
130 EFI_STATUS Status;
131 CM_OBJ_NODE *ObjNode;
132 CM_OBJECT_ID ArmNamespaceObjId;
133 CM_OBJECT_TOKEN NewToken;
134
135 // The dynamic repository must be able to receive objects.
136 if ((This == NULL) ||
137 (CmObjDesc == NULL) ||
138 (This->RepoState != DynRepoTransient))
139 {
140 ASSERT (0);
141 return EFI_INVALID_PARAMETER;
142 }
143
144 // Check the CmObjDesc:
145 // - only Arm objects are supported for now.
146 // - only EArmObjCmRef objects can be added as arrays.
147 ArmNamespaceObjId = GET_CM_OBJECT_ID (CmObjDesc->ObjectId);
148 if ((CmObjDesc->Size == 0) ||
149 (CmObjDesc->Count == 0) ||
150 (ArmNamespaceObjId >= EArmObjMax) ||
151 ((CmObjDesc->Count > 1) && (ArmNamespaceObjId != EArmObjCmRef)) ||
152 (GET_CM_NAMESPACE_ID (CmObjDesc->ObjectId) != EObjNameSpaceArm))
153 {
154 ASSERT (0);
155 return EFI_INVALID_PARAMETER;
156 }
157
158 // Generate a token.
159 NewToken = GenerateToken ();
160
161 // Create an ObjNode.
162 Status = AllocCmObjNode (CmObjDesc, NewToken, &ObjNode);
163 if (EFI_ERROR (Status)) {
164 ASSERT (0);
165 return Status;
166 }
167
168 // Fixup self-token if necessary.
169 Status = FixupCmObjectSelfToken (&ObjNode->CmObjDesc, NewToken);
170 if (EFI_ERROR (Status)) {
171 FreeCmObjNode (ObjNode);
172 ASSERT (0);
173 return Status;
174 }
175
176 // Add to link list.
177 InsertTailList (&This->ArmCmObjList[ArmNamespaceObjId], &ObjNode->Link);
178 This->ObjectCount += 1;
179
180 if (Token != NULL) {
181 *Token = NewToken;
182 }
183
184 return EFI_SUCCESS;
185}
186
187/** Group lists of CmObjNode from the ArmNameSpace to one array.
188
189 @param [in] This This dynamic platform repository.
190 @param [in] ArmObjIndex Index in EARM_OBJECT_ID
191 (must be < EArmObjMax).
192
193 @retval EFI_SUCCESS Success.
194 @retval EFI_INVALID_PARAMETER A parameter is invalid.
195 @retval EFI_BUFFER_TOO_SMALL Buffer too small.
196 @retval EFI_OUT_OF_RESOURCES An allocation has failed.
197**/
198STATIC
199EFI_STATUS
200EFIAPI
201GroupCmObjNodes (
202 IN DYNAMIC_PLATFORM_REPOSITORY_INFO *This,
203 IN UINT32 ArmObjIndex
204 )
205{
206 EFI_STATUS Status;
207 UINTN Count;
208 UINTN Size;
209 UINT32 CmObjId;
210 UINT8 *GroupedData;
211 UINT8 *Data;
212 CM_OBJ_DESCRIPTOR *CmObjDesc;
213 LIST_ENTRY *ListHead;
214 LIST_ENTRY *Link;
215
216 if ((This == NULL) ||
217 (ArmObjIndex >= EArmObjMax))
218 {
219 ASSERT (0);
220 return EFI_INVALID_PARAMETER;
221 }
222
223 Count = 0;
224 Size = 0;
225 CmObjId = CREATE_CM_ARM_OBJECT_ID (ArmObjIndex);
226 ListHead = &This->ArmCmObjList[ArmObjIndex];
227 Link = GetFirstNode (ListHead);
228
229 // Compute the total count and size of the CmObj in the list.
230 while (Link != ListHead) {
231 CmObjDesc = &((CM_OBJ_NODE *)Link)->CmObjDesc;
232
233 if (CmObjDesc->ObjectId != CmObjId) {
234 ASSERT (0);
235 return EFI_INVALID_PARAMETER;
236 }
237
238 if ((CmObjDesc->Count != 1) && (ArmObjIndex != EArmObjCmRef)) {
239 // We expect each descriptor to contain an individual object.
240 // EArmObjCmRef objects are counted as groups, so +1 as well.
241 ASSERT (0);
242 return EFI_INVALID_PARAMETER;
243 }
244
245 Count++;
246 Size += CmObjDesc->Size;
247
248 // Next Link
249 Link = GetNextNode (ListHead, Link);
250 } // while
251
252 if (Count == 0) {
253 // No objects found.
254 return EFI_SUCCESS;
255 }
256
257 GroupedData = AllocateZeroPool (Size);
258 if (GroupedData == NULL) {
259 ASSERT (0);
260 return EFI_OUT_OF_RESOURCES;
261 }
262
263 // Copy the Object Data and add to the TokenMapper.
264 Data = GroupedData;
265 Link = GetFirstNode (ListHead);
266 while (Link != ListHead) {
267 CmObjDesc = &((CM_OBJ_NODE *)Link)->CmObjDesc;
268 CopyMem (Data, CmObjDesc->Data, CmObjDesc->Size);
269
270 // Add the object to the Token Mapper.
271 // Note: The CmObject Data field of objects in the Token Mapper point
272 // to the memory in the GroupedData array.
273 Status = TokenMapperAddObject (
274 &This->TokenMapper,
275 ((CM_OBJ_NODE *)Link)->Token,
276 CmObjDesc->ObjectId,
277 CmObjDesc->Size,
278 Data
279 );
280 if (EFI_ERROR (Status)) {
281 FreePool (GroupedData);
282 return Status;
283 }
284
285 Data += CmObjDesc->Size;
286 Link = GetNextNode (ListHead, Link);
287 } // while
288
289 CmObjDesc = &This->ArmCmObjArray[ArmObjIndex];
290 CmObjDesc->ObjectId = CmObjId;
291 CmObjDesc->Size = (UINT32)Size;
292 CmObjDesc->Count = (UINT32)Count;
293 CmObjDesc->Data = GroupedData;
294
295 return Status;
296}
297
298/** Finalise the dynamic repository.
299
300 Finalising means:
301 - Preventing any further objects from being added.
302 - Allowing to get objects from the dynamic repository
303 (not possible before a call to this function).
304
305 @param [in] This This dynamic platform repository.
306
307 @retval EFI_SUCCESS Success.
308 @retval EFI_ALREADY_STARTED Instance already initialised.
309 @retval EFI_INVALID_PARAMETER A parameter is invalid.
310 @retval EFI_BUFFER_TOO_SMALL Buffer too small.
311 @retval EFI_OUT_OF_RESOURCES An allocation has failed.
312**/
313EFI_STATUS
314EFIAPI
315DynamicPlatRepoFinalise (
316 IN DYNAMIC_PLATFORM_REPOSITORY_INFO *This
317 )
318{
319 EFI_STATUS Status;
320 UINTN ArmObjIndex;
321
322 if ((This == NULL) ||
323 (This->RepoState != DynRepoTransient))
324 {
325 ASSERT (0);
326 return EFI_INVALID_PARAMETER;
327 }
328
329 // Prevent any further objects from being added.
330 This->RepoState = DynRepoFinalized;
331
332 // Initialise the token mapper.
333 Status = TokenMapperInitialise (&This->TokenMapper, This->ObjectCount);
334 if (EFI_ERROR (Status)) {
335 ASSERT (0);
336 return Status;
337 }
338
339 // For each CM_OBJECT_ID:
340 // - Convert the list of nodes to an array
341 // (the array is wrapped in a CmObjDesc).
342 // - Add the Token/CmObj binding to the token mapper.
343 for (ArmObjIndex = 0; ArmObjIndex < EArmObjMax; ArmObjIndex++) {
344 Status = GroupCmObjNodes (This, (UINT32)ArmObjIndex);
345 if (EFI_ERROR (Status)) {
346 ASSERT (0);
347 // Free the TokenMapper.
348 // Ignore the returned Status since we already failed.
349 TokenMapperShutdown (&This->TokenMapper);
350 return Status;
351 }
352 } // for
353
354 return EFI_SUCCESS;
355}
356
357/** Get a CmObj from the dynamic repository.
358
359 @param [in] This Pointer to the Dynamic Platform Repository.
360 @param [in] CmObjectId The Configuration Manager Object ID.
361 @param [in] Token An optional token identifying the object. If
362 unused this must be CM_NULL_TOKEN.
363 @param [in, out] CmObjDesc Pointer to the Configuration Manager Object
364 descriptor describing the requested Object.
365
366 @retval EFI_SUCCESS Success.
367 @retval EFI_INVALID_PARAMETER A parameter is invalid.
368 @retval EFI_NOT_FOUND The required object information is not found.
369**/
370EFI_STATUS
371EFIAPI
372DynamicPlatRepoGetObject (
373 IN DYNAMIC_PLATFORM_REPOSITORY_INFO *This,
374 IN CM_OBJECT_ID CmObjectId,
375 IN CM_OBJECT_TOKEN Token OPTIONAL,
376 IN OUT CM_OBJ_DESCRIPTOR *CmObjDesc
377 )
378{
379 EFI_STATUS Status;
380 CM_OBJ_DESCRIPTOR *Desc;
381 CM_OBJECT_ID ArmNamespaceObjId;
382
383 if ((This == NULL) ||
384 (CmObjDesc == NULL) ||
385 (This->RepoState != DynRepoFinalized))
386 {
387 ASSERT (0);
388 return EFI_INVALID_PARAMETER;
389 }
390
391 ArmNamespaceObjId = GET_CM_OBJECT_ID (CmObjectId);
392 if (ArmNamespaceObjId >= EArmObjMax) {
393 ASSERT (0);
394 return EFI_INVALID_PARAMETER;
395 }
396
397 if (Token != CM_NULL_TOKEN) {
398 // Search in the Token Mapper and return the object.
399 Status = TokenMapperGetObject (
400 &This->TokenMapper,
401 Token,
402 CmObjectId,
403 CmObjDesc
404 );
405 ASSERT_EFI_ERROR (Status);
406 return Status;
407 }
408
409 if (ArmNamespaceObjId == EArmObjCmRef) {
410 // EArmObjCmRef object must be requested using a valid token.
411 ASSERT (0);
412 return EFI_INVALID_PARAMETER;
413 }
414
415 Desc = &This->ArmCmObjArray[ArmNamespaceObjId];
416
417 // Nothing here.
418 if (Desc->Count == 0) {
419 return EFI_NOT_FOUND;
420 } else {
421 // Return the full array.
422 CmObjDesc->ObjectId = Desc->ObjectId;
423 CmObjDesc->Size = Desc->Size;
424 CmObjDesc->Data = Desc->Data;
425 CmObjDesc->Count = Desc->Count;
426 }
427
428 return EFI_SUCCESS;
429}
430
431/** Initialize the dynamic platform repository.
432
433 @param [out] DynPlatRepo If success, contains the initialised dynamic
434 platform repository.
435
436 @retval EFI_SUCCESS Success.
437 @retval EFI_INVALID_PARAMETER A parameter is invalid.
438 @retval EFI_OUT_OF_RESOURCES An allocation has failed.
439**/
440EFI_STATUS
441EFIAPI
442DynamicPlatRepoInit (
443 OUT DYNAMIC_PLATFORM_REPOSITORY_INFO **DynPlatRepo
444 )
445{
446 UINTN Index;
447 DYNAMIC_PLATFORM_REPOSITORY_INFO *Repo;
448
449 if (DynPlatRepo == NULL) {
450 ASSERT (0);
451 return EFI_INVALID_PARAMETER;
452 }
453
454 Repo = AllocateZeroPool (sizeof (DYNAMIC_PLATFORM_REPOSITORY_INFO));
455 if (Repo == NULL) {
456 ASSERT (0);
457 return EFI_OUT_OF_RESOURCES;
458 }
459
460 // Initialise the CmObject List.
461 for (Index = 0; Index < EArmObjMax; Index++) {
462 InitializeListHead (&Repo->ArmCmObjList[Index]);
463 }
464
465 Repo->ObjectCount = 0;
466 Repo->RepoState = DynRepoTransient;
467
468 *DynPlatRepo = Repo;
469
470 return EFI_SUCCESS;
471}
472
473/** Shutdown the dynamic platform repository.
474
475 Free all the memory allocated for the dynamic platform repository.
476
477 @param [in] DynPlatRepo The dynamic platform repository.
478
479 @retval EFI_INVALID_PARAMETER A parameter is invalid.
480 @retval EFI_SUCCESS Success.
481**/
482EFI_STATUS
483EFIAPI
484DynamicPlatRepoShutdown (
485 IN DYNAMIC_PLATFORM_REPOSITORY_INFO *DynPlatRepo
486 )
487{
488 EFI_STATUS Status;
489 UINT32 Index;
490 LIST_ENTRY *ListHead;
491 CM_OBJ_DESCRIPTOR *CmObjDesc;
492 VOID *Data;
493
494 if (DynPlatRepo == NULL) {
495 ASSERT (0);
496 return EFI_INVALID_PARAMETER;
497 }
498
499 // Free the list of objects.
500 for (Index = 0; Index < EArmObjMax; Index++) {
501 // Free all the nodes with this object Id.
502 ListHead = &DynPlatRepo->ArmCmObjList[Index];
503 while (!IsListEmpty (ListHead)) {
504 FreeCmObjNode ((CM_OBJ_NODE *)GetFirstNode (ListHead));
505 } // while
506 } // for
507
508 // Free the arrays.
509 CmObjDesc = DynPlatRepo->ArmCmObjArray;
510 for (Index = 0; Index < EArmObjMax; Index++) {
511 Data = CmObjDesc[Index].Data;
512 if (Data != NULL) {
513 FreePool (Data);
514 }
515 } // for
516
517 // Free the TokenMapper
518 Status = TokenMapperShutdown (&DynPlatRepo->TokenMapper);
519 ASSERT_EFI_ERROR (Status);
520 FreePool (DynPlatRepo);
521 return Status;
522}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette