1# Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR> 2# SPDX-License-Identifier: BSD-2-Clause-Patent 3 4# 5# This file is used to collect the Variable checking information 6# 7 8# # 9# Import Modules 10# 11from struct import pack, unpack 12import collections 13import copy 14from Common.VariableAttributes import VariableAttributes 15from Common.Misc import * 16import collections 17import Common.DataType as DataType 18 19var_info = collections.namedtuple("uefi_var", "pcdindex,pcdname,defaultstoragename,skuname,var_name, var_guid, var_offset,var_attribute,pcd_default_value, default_value, data_type,PcdDscLine,StructurePcd") 20NvStorageHeaderSize = 28 21VariableHeaderSize = 32 22 23class VariableMgr(object): 24 def __init__(self, DefaultStoreMap, SkuIdMap): 25 self.VarInfo = [] 26 self.DefaultStoreMap = DefaultStoreMap 27 self.SkuIdMap = SkuIdMap 28 self.VpdRegionSize = 0 29 self.VpdRegionOffset = 0 30 self.NVHeaderBuff = None 31 self.VarDefaultBuff = None 32 self.VarDeltaBuff = None 33 34 def append_variable(self, uefi_var): 35 self.VarInfo.append(uefi_var) 36 37 def SetVpdRegionMaxSize(self, maxsize): 38 self.VpdRegionSize = maxsize 39 40 def SetVpdRegionOffset(self, vpdoffset): 41 self.VpdRegionOffset = vpdoffset 42 43 def PatchNVStoreDefaultMaxSize(self, maxsize): 44 if not self.NVHeaderBuff: 45 return "" 46 self.NVHeaderBuff = self.NVHeaderBuff[:8] + pack("=Q", maxsize) 47 default_var_bin = VariableMgr.format_data(self.NVHeaderBuff + self.VarDefaultBuff + self.VarDeltaBuff) 48 value_str = "{" 49 default_var_bin_strip = [ data.strip("""'""") for data in default_var_bin] 50 value_str += ",".join(default_var_bin_strip) 51 value_str += "}" 52 return value_str 53 54 def combine_variable(self): 55 indexedvarinfo = collections.OrderedDict() 56 for item in self.VarInfo: 57 if (item.skuname, item.defaultstoragename, item.var_name, item.var_guid) not in indexedvarinfo: 58 indexedvarinfo[(item.skuname, item.defaultstoragename, item.var_name, item.var_guid) ] = [] 59 indexedvarinfo[(item.skuname, item.defaultstoragename, item.var_name, item.var_guid)].append(item) 60 for key in indexedvarinfo: 61 sku_var_info_offset_list = indexedvarinfo[key] 62 sku_var_info_offset_list.sort(key=lambda x:x.PcdDscLine) 63 FirstOffset = int(sku_var_info_offset_list[0].var_offset, 16) if sku_var_info_offset_list[0].var_offset.upper().startswith("0X") else int(sku_var_info_offset_list[0].var_offset) 64 fisrtvalue_list = sku_var_info_offset_list[0].default_value.strip("{").strip("}").split(",") 65 firstdata_type = sku_var_info_offset_list[0].data_type 66 if firstdata_type in DataType.TAB_PCD_NUMERIC_TYPES: 67 fisrtdata_flag = DataType.PACK_CODE_BY_SIZE[MAX_SIZE_TYPE[firstdata_type]] 68 fisrtdata = fisrtvalue_list[0] 69 fisrtvalue_list = [] 70 pack_data = pack(fisrtdata_flag, int(fisrtdata, 0)) 71 for data_byte in range(len(pack_data)): 72 fisrtvalue_list.append(hex(unpack("B", pack_data[data_byte:data_byte + 1])[0])) 73 newvalue_list = ["0x00"] * FirstOffset + fisrtvalue_list 74 75 for var_item in sku_var_info_offset_list[1:]: 76 CurOffset = int(var_item.var_offset, 16) if var_item.var_offset.upper().startswith("0X") else int(var_item.var_offset) 77 CurvalueList = var_item.default_value.strip("{").strip("}").split(",") 78 Curdata_type = var_item.data_type 79 if Curdata_type in DataType.TAB_PCD_NUMERIC_TYPES: 80 data_flag = DataType.PACK_CODE_BY_SIZE[MAX_SIZE_TYPE[Curdata_type]] 81 data = CurvalueList[0] 82 CurvalueList = [] 83 pack_data = pack(data_flag, int(data, 0)) 84 for data_byte in range(len(pack_data)): 85 CurvalueList.append(hex(unpack("B", pack_data[data_byte:data_byte + 1])[0])) 86 if CurOffset > len(newvalue_list): 87 newvalue_list = newvalue_list + ["0x00"] * (CurOffset - len(newvalue_list)) + CurvalueList 88 else: 89 newvalue_list[CurOffset : CurOffset + len(CurvalueList)] = CurvalueList 90 91 newvaluestr = "{" + ",".join(newvalue_list) +"}" 92 n = sku_var_info_offset_list[0] 93 indexedvarinfo[key] = [var_info(n.pcdindex, n.pcdname, n.defaultstoragename, n.skuname, n.var_name, n.var_guid, "0x00", n.var_attribute, newvaluestr, newvaluestr, DataType.TAB_VOID,n.PcdDscLine,n.StructurePcd)] 94 self.VarInfo = [item[0] for item in list(indexedvarinfo.values())] 95 96 def process_variable_data(self): 97 98 var_data = collections.defaultdict(collections.OrderedDict) 99 100 indexedvarinfo = collections.OrderedDict() 101 for item in self.VarInfo: 102 if item.pcdindex not in indexedvarinfo: 103 indexedvarinfo[item.pcdindex] = dict() 104 indexedvarinfo[item.pcdindex][(item.skuname, item.defaultstoragename)] = item 105 106 for index in indexedvarinfo: 107 sku_var_info = indexedvarinfo[index] 108 109 default_data_buffer = "" 110 others_data_buffer = "" 111 tail = None 112 default_sku_default = indexedvarinfo[index].get((DataType.TAB_DEFAULT, DataType.TAB_DEFAULT_STORES_DEFAULT)) 113 114 if default_sku_default.data_type not in DataType.TAB_PCD_NUMERIC_TYPES: 115 var_max_len = max(len(var_item.default_value.split(",")) for var_item in sku_var_info.values()) 116 if len(default_sku_default.default_value.split(",")) < var_max_len: 117 tail = ",".join("0x00" for i in range(var_max_len-len(default_sku_default.default_value.split(",")))) 118 119 default_data_buffer = VariableMgr.PACK_VARIABLES_DATA(default_sku_default.default_value, default_sku_default.data_type, tail) 120 121 default_data_array = () 122 for item in range(len(default_data_buffer)): 123 default_data_array += unpack("B", default_data_buffer[item:item + 1]) 124 125 var_data[(DataType.TAB_DEFAULT, DataType.TAB_DEFAULT_STORES_DEFAULT)][index] = (default_data_buffer, sku_var_info[(DataType.TAB_DEFAULT, DataType.TAB_DEFAULT_STORES_DEFAULT)]) 126 127 for (skuid, defaultstoragename) in indexedvarinfo[index]: 128 tail = None 129 if (skuid, defaultstoragename) == (DataType.TAB_DEFAULT, DataType.TAB_DEFAULT_STORES_DEFAULT): 130 continue 131 other_sku_other = indexedvarinfo[index][(skuid, defaultstoragename)] 132 133 if default_sku_default.data_type not in DataType.TAB_PCD_NUMERIC_TYPES: 134 if len(other_sku_other.default_value.split(",")) < var_max_len: 135 tail = ",".join("0x00" for i in range(var_max_len-len(other_sku_other.default_value.split(",")))) 136 137 others_data_buffer = VariableMgr.PACK_VARIABLES_DATA(other_sku_other.default_value, other_sku_other.data_type, tail) 138 139 others_data_array = () 140 for item in range(len(others_data_buffer)): 141 others_data_array += unpack("B", others_data_buffer[item:item + 1]) 142 143 data_delta = VariableMgr.calculate_delta(default_data_array, others_data_array) 144 145 var_data[(skuid, defaultstoragename)][index] = (data_delta, sku_var_info[(skuid, defaultstoragename)]) 146 return var_data 147 148 def new_process_varinfo(self): 149 self.combine_variable() 150 151 var_data = self.process_variable_data() 152 153 if not var_data: 154 return [] 155 156 pcds_default_data = var_data.get((DataType.TAB_DEFAULT, DataType.TAB_DEFAULT_STORES_DEFAULT), {}) 157 NvStoreDataBuffer = bytearray() 158 var_data_offset = collections.OrderedDict() 159 offset = NvStorageHeaderSize 160 for default_data, default_info in pcds_default_data.values(): 161 var_name_buffer = VariableMgr.PACK_VARIABLE_NAME(default_info.var_name) 162 163 vendorguid = default_info.var_guid.split('-') 164 165 if default_info.var_attribute: 166 var_attr_value, _ = VariableAttributes.GetVarAttributes(default_info.var_attribute) 167 else: 168 var_attr_value = 0x07 169 170 DataBuffer = VariableMgr.AlignData(var_name_buffer + default_data) 171 172 data_size = len(DataBuffer) 173 offset += VariableHeaderSize + len(default_info.var_name.split(",")) 174 var_data_offset[default_info.pcdindex] = offset 175 offset += data_size - len(default_info.var_name.split(",")) 176 177 var_header_buffer = VariableMgr.PACK_VARIABLE_HEADER(var_attr_value, len(default_info.var_name.split(",")), len (default_data), vendorguid) 178 NvStoreDataBuffer += (var_header_buffer + DataBuffer) 179 180 variable_storage_header_buffer = VariableMgr.PACK_VARIABLE_STORE_HEADER(len(NvStoreDataBuffer) + 28) 181 182 nv_default_part = VariableMgr.AlignData(VariableMgr.PACK_DEFAULT_DATA(0, 0, VariableMgr.unpack_data(variable_storage_header_buffer+NvStoreDataBuffer)), 8) 183 184 data_delta_structure_buffer = bytearray() 185 for skuname, defaultstore in var_data: 186 if (skuname, defaultstore) == (DataType.TAB_DEFAULT, DataType.TAB_DEFAULT_STORES_DEFAULT): 187 continue 188 pcds_sku_data = var_data[(skuname, defaultstore)] 189 delta_data_set = [] 190 for pcdindex in pcds_sku_data: 191 offset = var_data_offset[pcdindex] 192 delta_data, _ = pcds_sku_data[pcdindex] 193 delta_data = [(item[0] + offset, item[1]) for item in delta_data] 194 delta_data_set.extend(delta_data) 195 196 data_delta_structure_buffer += VariableMgr.AlignData(self.PACK_DELTA_DATA(skuname, defaultstore, delta_data_set), 8) 197 198 size = len(nv_default_part + data_delta_structure_buffer) + 16 199 maxsize = self.VpdRegionSize if self.VpdRegionSize else size 200 NV_Store_Default_Header = VariableMgr.PACK_NV_STORE_DEFAULT_HEADER(size, maxsize) 201 202 self.NVHeaderBuff = NV_Store_Default_Header 203 self.VarDefaultBuff =nv_default_part 204 self.VarDeltaBuff = data_delta_structure_buffer 205 return VariableMgr.format_data(NV_Store_Default_Header + nv_default_part + data_delta_structure_buffer) 206 207 208 @staticmethod 209 def format_data(data): 210 return [hex(item) for item in VariableMgr.unpack_data(data)] 211 212 @staticmethod 213 def unpack_data(data): 214 final_data = () 215 for item in range(len(data)): 216 final_data += unpack("B", data[item:item + 1]) 217 return final_data 218 219 @staticmethod 220 def calculate_delta(default, theother): 221 if len(default) - len(theother) != 0: 222 EdkLogger.error("build", FORMAT_INVALID, 'The variable data length is not the same for the same PCD.') 223 data_delta = [] 224 for i in range(len(default)): 225 if default[i] != theother[i]: 226 data_delta.append((i, theother[i])) 227 return data_delta 228 229 def dump(self): 230 231 default_var_bin = self.new_process_varinfo() 232 if default_var_bin: 233 value_str = "{" 234 default_var_bin_strip = [ data.strip("""'""") for data in default_var_bin] 235 value_str += ",".join(default_var_bin_strip) 236 value_str += "}" 237 return value_str 238 return "" 239 240 @staticmethod 241 def PACK_VARIABLE_STORE_HEADER(size): 242 #Signature: gEfiVariableGuid 243 Guid = "{ 0xddcf3616, 0x3275, 0x4164, { 0x98, 0xb6, 0xfe, 0x85, 0x70, 0x7f, 0xfe, 0x7d }}" 244 Guid = GuidStructureStringToGuidString(Guid) 245 GuidBuffer = PackGUID(Guid.split('-')) 246 247 SizeBuffer = pack('=L', size) 248 FormatBuffer = pack('=B', 0x5A) 249 StateBuffer = pack('=B', 0xFE) 250 reservedBuffer = pack('=H', 0) 251 reservedBuffer += pack('=L', 0) 252 253 return GuidBuffer + SizeBuffer + FormatBuffer + StateBuffer + reservedBuffer 254 255 @staticmethod 256 def PACK_NV_STORE_DEFAULT_HEADER(size, maxsize): 257 Signature = pack('=B', ord('N')) 258 Signature += pack("=B", ord('S')) 259 Signature += pack("=B", ord('D')) 260 Signature += pack("=B", ord('B')) 261 262 SizeBuffer = pack("=L", size) 263 MaxSizeBuffer = pack("=Q", maxsize) 264 265 return Signature + SizeBuffer + MaxSizeBuffer 266 267 @staticmethod 268 def PACK_VARIABLE_HEADER(attribute, namesize, datasize, vendorguid): 269 270 Buffer = pack('=H', 0x55AA) # pack StartID 271 Buffer += pack('=B', 0x3F) # pack State 272 Buffer += pack('=B', 0) # pack reserved 273 274 Buffer += pack('=L', attribute) 275 Buffer += pack('=L', namesize) 276 Buffer += pack('=L', datasize) 277 278 Buffer += PackGUID(vendorguid) 279 280 return Buffer 281 282 @staticmethod 283 def PACK_VARIABLES_DATA(var_value,data_type, tail = None): 284 Buffer = bytearray() 285 data_len = 0 286 if data_type == DataType.TAB_VOID: 287 for value_char in var_value.strip("{").strip("}").split(","): 288 Buffer += pack("=B", int(value_char, 16)) 289 data_len += len(var_value.split(",")) 290 if tail: 291 for value_char in tail.split(","): 292 Buffer += pack("=B", int(value_char, 16)) 293 data_len += len(tail.split(",")) 294 elif data_type == "BOOLEAN": 295 Buffer += pack("=B", True) if var_value.upper() in ["TRUE","1"] else pack("=B", False) 296 data_len += 1 297 elif data_type == DataType.TAB_UINT8: 298 Buffer += pack("=B", GetIntegerValue(var_value)) 299 data_len += 1 300 elif data_type == DataType.TAB_UINT16: 301 Buffer += pack("=H", GetIntegerValue(var_value)) 302 data_len += 2 303 elif data_type == DataType.TAB_UINT32: 304 Buffer += pack("=L", GetIntegerValue(var_value)) 305 data_len += 4 306 elif data_type == DataType.TAB_UINT64: 307 Buffer += pack("=Q", GetIntegerValue(var_value)) 308 data_len += 8 309 310 return Buffer 311 312 @staticmethod 313 def PACK_DEFAULT_DATA(defaultstoragename, skuid, var_value): 314 Buffer = bytearray() 315 Buffer += pack("=L", 4+8+8) 316 Buffer += pack("=Q", int(skuid)) 317 Buffer += pack("=Q", int(defaultstoragename)) 318 319 for item in var_value: 320 Buffer += pack("=B", item) 321 322 Buffer = pack("=L", len(Buffer)+4) + Buffer 323 324 return Buffer 325 326 def GetSkuId(self, skuname): 327 if skuname not in self.SkuIdMap: 328 return None 329 return self.SkuIdMap.get(skuname)[0] 330 331 def GetDefaultStoreId(self, dname): 332 if dname not in self.DefaultStoreMap: 333 return None 334 return self.DefaultStoreMap.get(dname)[0] 335 336 def PACK_DELTA_DATA(self, skuname, defaultstoragename, delta_list): 337 skuid = self.GetSkuId(skuname) 338 defaultstorageid = self.GetDefaultStoreId(defaultstoragename) 339 Buffer = bytearray() 340 Buffer += pack("=L", 4+8+8) 341 Buffer += pack("=Q", int(skuid)) 342 Buffer += pack("=Q", int(defaultstorageid)) 343 for (delta_offset, value) in delta_list: 344 Buffer += pack("=L", delta_offset) 345 Buffer = Buffer[:-1] + pack("=B", value) 346 347 Buffer = pack("=L", len(Buffer) + 4) + Buffer 348 349 return Buffer 350 351 @staticmethod 352 def AlignData(data, align = 4): 353 mybuffer = data 354 if (len(data) % align) > 0: 355 for i in range(align - (len(data) % align)): 356 mybuffer += pack("=B", 0) 357 358 return mybuffer 359 360 @staticmethod 361 def PACK_VARIABLE_NAME(var_name): 362 Buffer = bytearray() 363 for name_char in var_name.strip("{").strip("}").split(","): 364 Buffer += pack("=B", int(name_char, 16)) 365 366 return Buffer 367