|
| 1 | +# @file |
| 2 | +# Module contains helper classes and functions to work with Variable Policy structures |
| 3 | +# and substructures. |
| 4 | +# |
| 5 | +# Copyright (c) Microsoft Corporation |
| 6 | +# |
| 7 | +# SPDX-License-Identifier: BSD-2-Clause-Patent |
| 8 | +## |
| 9 | + |
| 10 | +import uuid |
| 11 | +import struct |
| 12 | +from edk2toollib.uefi.uefi_multi_phase import EfiVariableAttributes |
| 13 | + |
| 14 | + |
| 15 | +class VariableLockOnVarStatePolicy(object): |
| 16 | + # typedef struct { |
| 17 | + # EFI_GUID Namespace; |
| 18 | + # UINT8 Value; |
| 19 | + # UINT8 Reserved; |
| 20 | + # // CHAR16 Name[]; // Variable Length Field |
| 21 | + # } VARIABLE_LOCK_ON_VAR_STATE_POLICY; |
| 22 | + _HdrStructFormat = "<16sBB" |
| 23 | + _HdrStructSize = struct.calcsize(_HdrStructFormat) |
| 24 | + |
| 25 | + def __init__(self): |
| 26 | + self.Namespace = uuid.UUID(bytes=b'\x00' * 16) |
| 27 | + self.Value = 0 |
| 28 | + self.Name = None |
| 29 | + |
| 30 | + def __str__(self): |
| 31 | + return "VARIABLE_LOCK_ON_VAR_STATE_POLICY(%s, %d, %s)" % (self.Namespace, self.Value, self.Name) |
| 32 | + |
| 33 | + def decode(self, buffer): |
| 34 | + """ |
| 35 | + load this object from a bytes buffer |
| 36 | +
|
| 37 | + return any remaining buffer |
| 38 | + """ |
| 39 | + (_namespace, self.Value, _) = struct.unpack( |
| 40 | + self._HdrStructFormat, buffer[:self._HdrStructSize]) |
| 41 | + |
| 42 | + self.Namespace = uuid.UUID(bytes_le=_namespace) |
| 43 | + |
| 44 | + # Scan the rest of the buffer for a \x00\x00 to terminate the string. |
| 45 | + buffer = buffer[self._HdrStructSize:] |
| 46 | + if len(buffer) < 4: |
| 47 | + raise ValueError("Buffer too short!") |
| 48 | + |
| 49 | + string_end = None |
| 50 | + for i in range(0, len(buffer), 2): |
| 51 | + if buffer[i] == 0 and buffer[i + 1] == 0: |
| 52 | + string_end = i + 2 |
| 53 | + break |
| 54 | + |
| 55 | + if string_end is None: |
| 56 | + raise ValueError("String end not detected!") |
| 57 | + |
| 58 | + self.Name = buffer[:string_end].decode('utf-16').strip('\x00') |
| 59 | + |
| 60 | + return buffer[string_end:] |
| 61 | + |
| 62 | + |
| 63 | +class VariablePolicyEntry(object): |
| 64 | + # typedef struct { |
| 65 | + # UINT32 Version; |
| 66 | + # UINT16 Size; |
| 67 | + # UINT16 OffsetToName; |
| 68 | + # EFI_GUID Namespace; |
| 69 | + # UINT32 MinSize; |
| 70 | + # UINT32 MaxSize; |
| 71 | + # UINT32 AttributesMustHave; |
| 72 | + # UINT32 AttributesCantHave; |
| 73 | + # UINT8 LockPolicyType; |
| 74 | + # UINT8 Reserved[3]; |
| 75 | + # // UINT8 LockPolicy[]; // Variable Length Field |
| 76 | + # // CHAR16 Name[] // Variable Length Field |
| 77 | + # } VARIABLE_POLICY_ENTRY; |
| 78 | + _HdrStructFormat = "<IHH16sIIIIB3s" # spell-checker:disable-line |
| 79 | + _HdrStructSize = struct.calcsize(_HdrStructFormat) |
| 80 | + |
| 81 | + ENTRY_REVISION = 0x0001_0000 |
| 82 | + |
| 83 | + NO_MIN_SIZE = 0 |
| 84 | + NO_MAX_SIZE = 0xFFFF_FFFF |
| 85 | + NO_MUST_ATTR = 0 |
| 86 | + NO_CANT_ATTR = 0 |
| 87 | + |
| 88 | + TYPE_NO_LOCK = 0 |
| 89 | + TYPE_LOCK_NOW = 1 |
| 90 | + TYPE_LOCK_ON_CREATE = 2 |
| 91 | + TYPE_LOCK_ON_VAR_STATE = 3 |
| 92 | + |
| 93 | + LOCK_POLICY_STRING_MAP = { |
| 94 | + TYPE_NO_LOCK: "NONE", |
| 95 | + TYPE_LOCK_NOW: "NOW", |
| 96 | + TYPE_LOCK_ON_CREATE: "ON_CREATE", |
| 97 | + TYPE_LOCK_ON_VAR_STATE: "ON_VAR_STATE", |
| 98 | + } |
| 99 | + |
| 100 | + def __init__(self): |
| 101 | + self.Version = VariablePolicyEntry.ENTRY_REVISION |
| 102 | + self.Size = VariablePolicyEntry._HdrStructSize |
| 103 | + self.OffsetToName = self.Size |
| 104 | + self.Namespace = uuid.UUID(bytes=b'\x00' * 16) |
| 105 | + self.MinSize = VariablePolicyEntry.NO_MIN_SIZE |
| 106 | + self.MaxSize = VariablePolicyEntry.NO_MAX_SIZE |
| 107 | + self.AttributesMustHave = VariablePolicyEntry.NO_MUST_ATTR |
| 108 | + self.AttributesCantHave = VariablePolicyEntry.NO_CANT_ATTR |
| 109 | + self.LockPolicyType = VariablePolicyEntry.TYPE_NO_LOCK |
| 110 | + self.LockPolicy = None |
| 111 | + self.Name = None |
| 112 | + |
| 113 | + def __str__(self): |
| 114 | + result = "VARIABLE_POLICY_ENTRY(%s, %s)\n" % (self.Namespace, self.Name) |
| 115 | + |
| 116 | + if self.LockPolicyType in (VariablePolicyEntry.TYPE_NO_LOCK, |
| 117 | + VariablePolicyEntry.TYPE_LOCK_NOW, |
| 118 | + VariablePolicyEntry.TYPE_LOCK_ON_CREATE): |
| 119 | + result += "\tLock = %s\n" % VariablePolicyEntry.LOCK_POLICY_STRING_MAP[self.LockPolicyType] |
| 120 | + elif self.LockPolicyType is VariablePolicyEntry.TYPE_LOCK_ON_VAR_STATE: |
| 121 | + result += "\tLock = %s\n" % self.LockPolicy |
| 122 | + |
| 123 | + result += "\tMin = 0x%08X, Max = 0x%08X, Must = 0x%08X, Cant = 0x%08X\n" % ( |
| 124 | + self.MinSize, self.MaxSize, self.AttributesMustHave, self.AttributesCantHave) |
| 125 | + |
| 126 | + return result |
| 127 | + |
| 128 | + @staticmethod |
| 129 | + def csv_header(): |
| 130 | + """returns a list containing the names of the ordered columns that are produced by csv_row()""" |
| 131 | + return ['Namespace', 'Name', 'LockPolicyType', 'VarStateNamespace', 'VarStateName', |
| 132 | + 'VarStateValue', 'MinSize', 'MaxSize', 'AttributesMustHave', 'AttributesCantHave'] |
| 133 | + |
| 134 | + def csv_row(self, guid_xref: dict = None): |
| 135 | + """ |
| 136 | + returns a list containing the elements of this structure (in the same order as the csv_header) |
| 137 | + ready to be written to a csv file |
| 138 | +
|
| 139 | + guid_xref - a dictionary of GUID/name substitutions where the key is a uuid object |
| 140 | + and the value is a string |
| 141 | + """ |
| 142 | + if guid_xref is None: |
| 143 | + guid_xref = {} |
| 144 | + |
| 145 | + result = [guid_xref.get(self.Namespace, self.Namespace), |
| 146 | + self.Name, VariablePolicyEntry.LOCK_POLICY_STRING_MAP[self.LockPolicyType]] |
| 147 | + |
| 148 | + if self.LockPolicyType in (VariablePolicyEntry.TYPE_NO_LOCK, |
| 149 | + VariablePolicyEntry.TYPE_LOCK_NOW, |
| 150 | + VariablePolicyEntry.TYPE_LOCK_ON_CREATE): |
| 151 | + result += ['N/A', 'N/A', 'N/A'] |
| 152 | + elif self.LockPolicyType is VariablePolicyEntry.TYPE_LOCK_ON_VAR_STATE: |
| 153 | + result += [guid_xref.get(self.LockPolicy.Namespace, self.LockPolicy.Namespace), |
| 154 | + self.LockPolicy.Name, self.LockPolicy.Value] |
| 155 | + |
| 156 | + result += ["0x%08X" % self.MinSize, |
| 157 | + "0x%08X" % self.MaxSize, |
| 158 | + str(EfiVariableAttributes(self.AttributesMustHave)), |
| 159 | + str(EfiVariableAttributes(self.AttributesCantHave))] |
| 160 | + |
| 161 | + return result |
| 162 | + |
| 163 | + def decode(self, buffer): |
| 164 | + """ |
| 165 | + load this object from a bytes buffer |
| 166 | +
|
| 167 | + return any remaining buffer |
| 168 | + """ |
| 169 | + (self.Version, self.Size, self.OffsetToName, _namespace, |
| 170 | + self.MinSize, self.MaxSize, self.AttributesMustHave, |
| 171 | + self.AttributesCantHave, self.LockPolicyType, _) = struct.unpack( |
| 172 | + self._HdrStructFormat, buffer[:self._HdrStructSize]) |
| 173 | + |
| 174 | + if self.Version != VariablePolicyEntry.ENTRY_REVISION: |
| 175 | + raise ValueError("Unknown structure version!") |
| 176 | + if self.LockPolicyType not in VariablePolicyEntry.LOCK_POLICY_STRING_MAP: |
| 177 | + raise ValueError("Unknown LockPolicyType!") |
| 178 | + |
| 179 | + self.Namespace = uuid.UUID(bytes_le=_namespace) |
| 180 | + |
| 181 | + if self.OffsetToName != self.Size: |
| 182 | + self.Name = buffer[self.OffsetToName:self.Size].decode('utf-16').strip('\x00') |
| 183 | + |
| 184 | + if self.LockPolicyType == VariablePolicyEntry.TYPE_LOCK_ON_VAR_STATE: |
| 185 | + self.LockPolicy = VariableLockOnVarStatePolicy() |
| 186 | + self.LockPolicy.decode(buffer[self._HdrStructSize:self.OffsetToName]) |
| 187 | + |
| 188 | + return buffer[self.Size:] |
0 commit comments