CloverBootloader/Library/OcTemplateLib/OcTemplateLib.c
2020-07-09 22:06:48 +03:00

324 lines
6.9 KiB
C

/** @file
OcTemplateLib
Copyright (c) 2018, vit9696
All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <Library/OcTemplateLib.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/OcGuardLib.h>
#define PRIV_OC_BLOB_FIELDS(_, __) \
OC_BLOB (CHAR8, [], {0}, _, __)
OC_DECLARE (PRIV_OC_BLOB)
#define PRIV_OC_MAP_FIELDS(_, __) \
OC_MAP (PRIV_OC_BLOB, PRIV_OC_BLOB, _, __)
OC_DECLARE (PRIV_OC_MAP)
#define PRIV_OC_ARRAY_FIELDS(_, __) \
OC_ARRAY (PRIV_OC_BLOB, _, __)
OC_DECLARE (PRIV_OC_ARRAY)
typedef union PRIV_OC_LIST_ {
PRIV_OC_MAP Map;
PRIV_OC_ARRAY Array;
} PRIV_OC_LIST;
//
// We have to be a bit careful about this hack, so assert that type layouts match at the very least.
//
#if 0 // defined(__GNUC__) || defined(__clang__)
STATIC_ASSERT(OFFSET_OF (PRIV_OC_ARRAY, Count) == OFFSET_OF (PRIV_OC_MAP, Count), "PRIV_OC_ARRAY vs PRIV_OC_MAP");
STATIC_ASSERT(OFFSET_OF (PRIV_OC_ARRAY, AllocCount) == OFFSET_OF (PRIV_OC_MAP, AllocCount), "PRIV_OC_ARRAY vs PRIV_OC_MAP");
STATIC_ASSERT(OFFSET_OF (PRIV_OC_ARRAY, Construct) == OFFSET_OF (PRIV_OC_MAP, Construct), "PRIV_OC_ARRAY vs PRIV_OC_MAP");
STATIC_ASSERT(OFFSET_OF (PRIV_OC_ARRAY, Destruct) == OFFSET_OF (PRIV_OC_MAP, Destruct), "PRIV_OC_ARRAY vs PRIV_OC_MAP");
STATIC_ASSERT(OFFSET_OF (PRIV_OC_ARRAY, Values) == OFFSET_OF (PRIV_OC_MAP, Values), "PRIV_OC_ARRAY vs PRIV_OC_MAP");
STATIC_ASSERT(OFFSET_OF (PRIV_OC_ARRAY, ValueSize) == OFFSET_OF (PRIV_OC_MAP, ValueSize), "PRIV_OC_ARRAY vs PRIV_OC_MAP");
#endif
VOID
OcFreePointer (
VOID *Pointer,
UINT32 Size
)
{
VOID **Field = (VOID **) Pointer;
if (*Field) {
FreePool (*Field);
*Field = NULL;
}
}
VOID
OcZeroField (
VOID *Pointer,
UINT32 Size
)
{
ZeroMem (Pointer, Size);
}
VOID
OcDestructEmpty (
VOID *Pointer,
UINT32 Size
)
{
(VOID) Pointer;
(VOID) Size;
}
STATIC
VOID
OcFreeList (
VOID *Pointer,
BOOLEAN HasKeys
)
{
UINT32 Index;
PRIV_OC_LIST *List;
List = (PRIV_OC_LIST *) Pointer;
for (Index = 0; Index < List->Array.Count; Index++) {
List->Array.Destruct (List->Array.Values[Index], List->Array.ValueSize);
FreePool (List->Array.Values[Index]);
if (HasKeys) {
List->Map.KeyDestruct (List->Map.Keys[Index], List->Map.KeySize);
FreePool (List->Map.Keys[Index]);
}
}
OcFreePointer (&List->Array.Values, List->Array.AllocCount * List->Array.ValueSize);
if (HasKeys) {
OcFreePointer (&List->Map.Keys, List->Array.AllocCount * List->Map.KeySize);
}
List->Array.Count = 0;
List->Array.AllocCount = 0;
}
VOID
OcFreeMap (
VOID *Pointer,
UINT32 Size
)
{
OcFreeList (Pointer, TRUE);
}
VOID
OcFreeArray (
VOID *Pointer,
UINT32 Size
)
{
OcFreeList (Pointer, FALSE);
}
VOID *
OcBlobAllocate (
VOID *Pointer,
UINT32 Size,
UINT32 **OutSize OPTIONAL
)
{
PRIV_OC_BLOB *Blob;
VOID *DynValue;
Blob = (PRIV_OC_BLOB *) Pointer;
DEBUG ((DEBUG_VERBOSE, "OCTPL: Allocating %u bytes in blob %p with size %u/%u curr %p\n",
Size, Blob, Blob->Size, Blob->MaxSize, Blob->DynValue));
//
// We fit into static space
//
if (Size <= Blob->MaxSize) {
OcFreePointer (&Blob->DynValue, Blob->Size);
Blob->Size = Size;
if (OutSize != NULL) {
*OutSize = &Blob->Size;
}
return Blob->Value;
}
//
// We do not fit into dynamic space
//
if (Size > Blob->Size) {
OcFreePointer (&Blob->DynValue, Blob->Size);
DynValue = AllocatePool (Size);
if (DynValue == NULL) {
DEBUG ((DEBUG_VERBOSE, "OCTPL: Failed to fit %u bytes in OC_BLOB\n", Size));
return NULL;
}
//
// Propagate default value.
//
CopyMem (DynValue, Blob->Value, Blob->MaxSize);
Blob->DynValue = DynValue;
}
Blob->Size = Size;
if (OutSize != NULL) {
*OutSize = &Blob->Size;
}
return Blob->DynValue;
}
BOOLEAN
OcListEntryAllocate (
VOID *Pointer,
VOID **Value,
VOID **Key
)
{
PRIV_OC_LIST *List;
UINT32 Count;
UINT32 AllocCount;
VOID **NewValues;
VOID **NewKeys;
List = (PRIV_OC_LIST *) Pointer;
//
// Prepare new pair.
//
*Value = AllocatePool (List->Array.ValueSize);
if (*Value == NULL) {
return FALSE;
}
if (Key != NULL) {
*Key = AllocatePool (List->Map.KeySize);
if (*Key == NULL) {
FreePool (*Value);
return FALSE;
}
}
//
// Initialize new pair.
//
List->Array.Construct (*Value, List->Array.ValueSize);
if (Key != NULL) {
List->Map.KeyConstruct (*Key, List->Map.KeySize);
}
Count = 0;
AllocCount = 1;
//
// Push new entry if there is enough room.
//
if (List->Array.Values != NULL) {
Count = List->Array.Count;
AllocCount = List->Array.AllocCount;
if (AllocCount > Count) {
List->Array.Count++;
List->Array.Values[Count] = *Value;
if (Key != NULL) {
List->Map.Keys[Count] = *Key;
}
return TRUE;
}
}
//
// Allocate twice more room and destruct on failure.
//
AllocCount *= 2;
NewValues = (VOID **) AllocatePool (
sizeof (VOID *) * AllocCount
);
if (NewValues == NULL) {
List->Array.Destruct (*Value, List->Array.ValueSize);
FreePool (*Value);
if (Key != NULL) {
List->Map.KeyDestruct (*Key, List->Map.KeySize);
FreePool (*Key);
}
return FALSE;
}
if (Key != NULL) {
NewKeys = (VOID **) AllocatePool (
sizeof (VOID *) * AllocCount
);
if (NewKeys == NULL) {
List->Array.Destruct (*Value, List->Array.ValueSize);
List->Map.KeyDestruct (*Key, List->Map.KeySize);
FreePool (NewValues);
FreePool (*Value);
FreePool (*Key);
return FALSE;
}
} else {
NewKeys = NULL;
}
//
// Insert and return.
//
if (List->Array.Values != NULL) {
CopyMem (
&NewValues[0],
&List->Array.Values[0],
sizeof (VOID *) * Count
);
FreePool (List->Array.Values);
}
if (Key != NULL && List->Map.Keys != NULL) {
CopyMem (
&NewKeys[0],
&List->Map.Keys[0],
sizeof (VOID *) * Count
);
FreePool (List->Map.Keys);
}
List->Array.Count++;
List->Array.AllocCount = AllocCount;
NewValues[Count] = *Value;
List->Array.Values = (PRIV_OC_BLOB **) NewValues;
if (Key != NULL) {
NewKeys[Count] = *Key;
List->Map.Keys = (PRIV_OC_BLOB **) NewKeys;
}
return TRUE;
}
OC_BLOB_STRUCTORS (OC_STRING)
OC_BLOB_STRUCTORS (OC_DATA)
OC_MAP_STRUCTORS (OC_ASSOC)