]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/AutoGen/GenVar.py
BaseTool: Support different PCDs that refers to the same EFI variable.
[mirror_edk2.git] / BaseTools / Source / Python / AutoGen / GenVar.py
1 # Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
2 # This program and the accompanying materials
3 # are licensed and made available under the terms and conditions of the BSD License
4 # which accompanies this distribution. The full text of the license may be found at
5 # http://opensource.org/licenses/bsd-license.php
6 #
7 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
8 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
9
10 #
11 # This file is used to collect the Variable checking information
12 #
13
14 # #
15 # Import Modules
16 #
17 from struct import pack, unpack
18 import collections
19 import copy
20 from Common.VariableAttributes import VariableAttributes
21 from Common.Misc import *
22 import collections
23 import Common.DataType as DataType
24
25 var_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")
26 NvStorageHeaderSize = 28
27 VariableHeaderSize = 32
28
29 class VariableMgr(object):
30 def __init__(self, DefaultStoreMap, SkuIdMap):
31 self.VarInfo = []
32 self.DefaultStoreMap = DefaultStoreMap
33 self.SkuIdMap = SkuIdMap
34 self.VpdRegionSize = 0
35 self.VpdRegionOffset = 0
36 self.NVHeaderBuff = None
37 self.VarDefaultBuff = None
38 self.VarDeltaBuff = None
39
40 def append_variable(self, uefi_var):
41 self.VarInfo.append(uefi_var)
42
43 def SetVpdRegionMaxSize(self, maxsize):
44 self.VpdRegionSize = maxsize
45
46 def SetVpdRegionOffset(self, vpdoffset):
47 self.VpdRegionOffset = vpdoffset
48
49 def PatchNVStoreDefaultMaxSize(self, maxsize):
50 if not self.NVHeaderBuff:
51 return ""
52 self.NVHeaderBuff = self.NVHeaderBuff[:8] + pack("=Q", maxsize)
53 default_var_bin = VariableMgr.format_data(self.NVHeaderBuff + self.VarDefaultBuff + self.VarDeltaBuff)
54 value_str = "{"
55 default_var_bin_strip = [ data.strip("""'""") for data in default_var_bin]
56 value_str += ",".join(default_var_bin_strip)
57 value_str += "}"
58 return value_str
59 def Do_combine(self,sku_var_info_offset_list):
60 newvalue = {}
61 for item in sku_var_info_offset_list:
62 data_type = item.data_type
63 value_list = item.default_value.strip("{").strip("}").split(",")
64 if data_type in DataType.TAB_PCD_NUMERIC_TYPES:
65 data_flag = DataType.PACK_CODE_BY_SIZE[MAX_SIZE_TYPE[data_type]]
66 data = value_list[0]
67 value_list = []
68 for data_byte in pack(data_flag, int(data, 16) if data.upper().startswith('0X') else int(data)):
69 value_list.append(hex(unpack("B", data_byte)[0]))
70 newvalue[int(item.var_offset, 16) if item.var_offset.upper().startswith("0X") else int(item.var_offset)] = value_list
71 try:
72 newvaluestr = "{" + ",".join(VariableMgr.assemble_variable(newvalue)) +"}"
73 except:
74 EdkLogger.error("build", AUTOGEN_ERROR, "Variable offset conflict in PCDs: %s \n" % (" and ".join(item.pcdname for item in sku_var_info_offset_list)))
75 return newvaluestr
76 def Do_Merge(self,sku_var_info_offset_list):
77 StructrurePcds = sorted([item for item in sku_var_info_offset_list if item.StructurePcd], key = lambda x: x.PcdDscLine, reverse =True )
78 Base = StructrurePcds[0]
79 BaseValue = Base.default_value.strip("{").strip("}").split(",")
80 Override = [item for item in sku_var_info_offset_list if not item.StructurePcd and item.PcdDscLine > Base.PcdDscLine]
81 newvalue = {}
82 for item in Override:
83 data_type = item.data_type
84 value_list = item.default_value.strip("{").strip("}").split(",")
85 if data_type in DataType.TAB_PCD_NUMERIC_TYPES:
86 data_flag = DataType.PACK_CODE_BY_SIZE[MAX_SIZE_TYPE[data_type]]
87 data = value_list[0]
88 value_list = []
89 for data_byte in pack(data_flag, int(data, 16) if data.upper().startswith('0X') else int(data)):
90 value_list.append(hex(unpack("B", data_byte)[0]))
91 newvalue[int(item.var_offset, 16) if item.var_offset.upper().startswith("0X") else int(item.var_offset)] = (value_list,item.pcdname,item.PcdDscLine)
92 for offset in newvalue:
93 value_list,itemPcdname,itemPcdDscLine = newvalue[offset]
94 if offset > len(BaseValue) or (offset + len(value_list) > len(BaseValue)):
95 EdkLogger.error("build", AUTOGEN_ERROR, "The EFI Variable referred by PCD %s in line %s exceeds variable size: %s\n" % (itemPcdname,itemPcdDscLine,hex(len(BaseValue))))
96 for i in xrange(len(value_list)):
97 BaseValue[offset + i] = value_list[i]
98 newvaluestr = "{" + ",".join(BaseValue) +"}"
99 return newvaluestr
100 def NeedMerge(self,sku_var_info_offset_list):
101 if [item for item in sku_var_info_offset_list if item.StructurePcd]:
102 return True
103 return False
104 def combine_variable(self):
105 indexedvarinfo = collections.OrderedDict()
106 for item in self.VarInfo:
107 if (item.skuname, item.defaultstoragename, item.var_name, item.var_guid) not in indexedvarinfo:
108 indexedvarinfo[(item.skuname, item.defaultstoragename, item.var_name, item.var_guid) ] = []
109 indexedvarinfo[(item.skuname, item.defaultstoragename, item.var_name, item.var_guid)].append(item)
110 for key in indexedvarinfo:
111 sku_var_info_offset_list = indexedvarinfo[key]
112 if len(sku_var_info_offset_list) == 1:
113 continue
114
115 n = sku_var_info_offset_list[0]
116
117 if self.NeedMerge(sku_var_info_offset_list):
118 newvaluestr = self.Do_Merge(sku_var_info_offset_list)
119 else:
120 newvaluestr = self.Do_combine(sku_var_info_offset_list)
121
122 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)]
123 self.VarInfo = [item[0] for item in indexedvarinfo.values()]
124
125 @staticmethod
126 def assemble_variable(valuedict):
127 ordered_valuedict_keys = sorted(valuedict.keys())
128 var_value = []
129 for current_valuedict_key in ordered_valuedict_keys:
130 if current_valuedict_key < len(var_value):
131 raise
132 for _ in xrange(current_valuedict_key - len(var_value)):
133 var_value.append('0x00')
134 var_value += valuedict[current_valuedict_key]
135 return var_value
136
137 def process_variable_data(self):
138
139 var_data = collections.defaultdict(collections.OrderedDict)
140
141 indexedvarinfo = collections.OrderedDict()
142 for item in self.VarInfo:
143 if item.pcdindex not in indexedvarinfo:
144 indexedvarinfo[item.pcdindex] = dict()
145 indexedvarinfo[item.pcdindex][(item.skuname, item.defaultstoragename)] = item
146
147 for index in indexedvarinfo:
148 sku_var_info = indexedvarinfo[index]
149
150 default_data_buffer = ""
151 others_data_buffer = ""
152 tail = None
153 default_sku_default = indexedvarinfo[index].get((DataType.TAB_DEFAULT, DataType.TAB_DEFAULT_STORES_DEFAULT))
154
155 if default_sku_default.data_type not in DataType.TAB_PCD_NUMERIC_TYPES:
156 var_max_len = max(len(var_item.default_value.split(",")) for var_item in sku_var_info.values())
157 if len(default_sku_default.default_value.split(",")) < var_max_len:
158 tail = ",".join("0x00" for i in range(var_max_len-len(default_sku_default.default_value.split(","))))
159
160 default_data_buffer = VariableMgr.PACK_VARIABLES_DATA(default_sku_default.default_value, default_sku_default.data_type, tail)
161
162 default_data_array = ()
163 for item in default_data_buffer:
164 default_data_array += unpack("B", item)
165
166 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)])
167
168 for (skuid, defaultstoragename) in indexedvarinfo[index]:
169 tail = None
170 if (skuid, defaultstoragename) == (DataType.TAB_DEFAULT, DataType.TAB_DEFAULT_STORES_DEFAULT):
171 continue
172 other_sku_other = indexedvarinfo[index][(skuid, defaultstoragename)]
173
174 if default_sku_default.data_type not in DataType.TAB_PCD_NUMERIC_TYPES:
175 if len(other_sku_other.default_value.split(",")) < var_max_len:
176 tail = ",".join("0x00" for i in range(var_max_len-len(other_sku_other.default_value.split(","))))
177
178 others_data_buffer = VariableMgr.PACK_VARIABLES_DATA(other_sku_other.default_value, other_sku_other.data_type, tail)
179
180 others_data_array = ()
181 for item in others_data_buffer:
182 others_data_array += unpack("B", item)
183
184 data_delta = VariableMgr.calculate_delta(default_data_array, others_data_array)
185
186 var_data[(skuid, defaultstoragename)][index] = (data_delta, sku_var_info[(skuid, defaultstoragename)])
187 return var_data
188
189 def new_process_varinfo(self):
190 self.combine_variable()
191
192 var_data = self.process_variable_data()
193
194 if not var_data:
195 return []
196
197 pcds_default_data = var_data.get((DataType.TAB_DEFAULT, DataType.TAB_DEFAULT_STORES_DEFAULT), {})
198 NvStoreDataBuffer = ""
199 var_data_offset = collections.OrderedDict()
200 offset = NvStorageHeaderSize
201 for default_data, default_info in pcds_default_data.values():
202 var_name_buffer = VariableMgr.PACK_VARIABLE_NAME(default_info.var_name)
203
204 vendorguid = default_info.var_guid.split('-')
205
206 if default_info.var_attribute:
207 var_attr_value, _ = VariableAttributes.GetVarAttributes(default_info.var_attribute)
208 else:
209 var_attr_value = 0x07
210
211 DataBuffer = VariableMgr.AlignData(var_name_buffer + default_data)
212
213 data_size = len(DataBuffer)
214 offset += VariableHeaderSize + len(default_info.var_name.split(","))
215 var_data_offset[default_info.pcdindex] = offset
216 offset += data_size - len(default_info.var_name.split(","))
217
218 var_header_buffer = VariableMgr.PACK_VARIABLE_HEADER(var_attr_value, len(default_info.var_name.split(",")), len (default_data), vendorguid)
219 NvStoreDataBuffer += (var_header_buffer + DataBuffer)
220
221 variable_storage_header_buffer = VariableMgr.PACK_VARIABLE_STORE_HEADER(len(NvStoreDataBuffer) + 28)
222
223 nv_default_part = VariableMgr.AlignData(VariableMgr.PACK_DEFAULT_DATA(0, 0, VariableMgr.unpack_data(variable_storage_header_buffer+NvStoreDataBuffer)), 8)
224
225 data_delta_structure_buffer = ""
226 for skuname, defaultstore in var_data:
227 if (skuname, defaultstore) == (DataType.TAB_DEFAULT, DataType.TAB_DEFAULT_STORES_DEFAULT):
228 continue
229 pcds_sku_data = var_data[(skuname, defaultstore)]
230 delta_data_set = []
231 for pcdindex in pcds_sku_data:
232 offset = var_data_offset[pcdindex]
233 delta_data, _ = pcds_sku_data[pcdindex]
234 delta_data = [(item[0] + offset, item[1]) for item in delta_data]
235 delta_data_set.extend(delta_data)
236
237 data_delta_structure_buffer += VariableMgr.AlignData(self.PACK_DELTA_DATA(skuname, defaultstore, delta_data_set), 8)
238
239 size = len(nv_default_part + data_delta_structure_buffer) + 16
240 maxsize = self.VpdRegionSize if self.VpdRegionSize else size
241 NV_Store_Default_Header = VariableMgr.PACK_NV_STORE_DEFAULT_HEADER(size, maxsize)
242
243 self.NVHeaderBuff = NV_Store_Default_Header
244 self.VarDefaultBuff =nv_default_part
245 self.VarDeltaBuff = data_delta_structure_buffer
246 return VariableMgr.format_data(NV_Store_Default_Header + nv_default_part + data_delta_structure_buffer)
247
248
249 @staticmethod
250 def format_data(data):
251 return [hex(item) for item in VariableMgr.unpack_data(data)]
252
253 @staticmethod
254 def unpack_data(data):
255 final_data = ()
256 for item in data:
257 final_data += unpack("B", item)
258 return final_data
259
260 @staticmethod
261 def calculate_delta(default, theother):
262 if len(default) - len(theother) != 0:
263 EdkLogger.error("build", FORMAT_INVALID, 'The variable data length is not the same for the same PCD.')
264 data_delta = []
265 for i in range(len(default)):
266 if default[i] != theother[i]:
267 data_delta.append((i, theother[i]))
268 return data_delta
269
270 def dump(self):
271
272 default_var_bin = self.new_process_varinfo()
273 if default_var_bin:
274 value_str = "{"
275 default_var_bin_strip = [ data.strip("""'""") for data in default_var_bin]
276 value_str += ",".join(default_var_bin_strip)
277 value_str += "}"
278 return value_str
279 return ""
280
281 @staticmethod
282 def PACK_VARIABLE_STORE_HEADER(size):
283 #Signature: gEfiVariableGuid
284 Guid = "{ 0xddcf3616, 0x3275, 0x4164, { 0x98, 0xb6, 0xfe, 0x85, 0x70, 0x7f, 0xfe, 0x7d }}"
285 Guid = GuidStructureStringToGuidString(Guid)
286 GuidBuffer = PackGUID(Guid.split('-'))
287
288 SizeBuffer = pack('=L', size)
289 FormatBuffer = pack('=B', 0x5A)
290 StateBuffer = pack('=B', 0xFE)
291 reservedBuffer = pack('=H', 0)
292 reservedBuffer += pack('=L', 0)
293
294 return GuidBuffer + SizeBuffer + FormatBuffer + StateBuffer + reservedBuffer
295
296 @staticmethod
297 def PACK_NV_STORE_DEFAULT_HEADER(size, maxsize):
298 Signature = pack('=B', ord('N'))
299 Signature += pack("=B", ord('S'))
300 Signature += pack("=B", ord('D'))
301 Signature += pack("=B", ord('B'))
302
303 SizeBuffer = pack("=L", size)
304 MaxSizeBuffer = pack("=Q", maxsize)
305
306 return Signature + SizeBuffer + MaxSizeBuffer
307
308 @staticmethod
309 def PACK_VARIABLE_HEADER(attribute, namesize, datasize, vendorguid):
310
311 Buffer = pack('=H', 0x55AA) # pack StartID
312 Buffer += pack('=B', 0x3F) # pack State
313 Buffer += pack('=B', 0) # pack reserved
314
315 Buffer += pack('=L', attribute)
316 Buffer += pack('=L', namesize)
317 Buffer += pack('=L', datasize)
318
319 Buffer += PackGUID(vendorguid)
320
321 return Buffer
322
323 @staticmethod
324 def PACK_VARIABLES_DATA(var_value,data_type, tail = None):
325 Buffer = ""
326 data_len = 0
327 if data_type == DataType.TAB_VOID:
328 for value_char in var_value.strip("{").strip("}").split(","):
329 Buffer += pack("=B", int(value_char, 16))
330 data_len += len(var_value.split(","))
331 if tail:
332 for value_char in tail.split(","):
333 Buffer += pack("=B", int(value_char, 16))
334 data_len += len(tail.split(","))
335 elif data_type == "BOOLEAN":
336 Buffer += pack("=B", True) if var_value.upper() in ["TRUE","1"] else pack("=B", False)
337 data_len += 1
338 elif data_type == DataType.TAB_UINT8:
339 Buffer += pack("=B", GetIntegerValue(var_value))
340 data_len += 1
341 elif data_type == DataType.TAB_UINT16:
342 Buffer += pack("=H", GetIntegerValue(var_value))
343 data_len += 2
344 elif data_type == DataType.TAB_UINT32:
345 Buffer += pack("=L", GetIntegerValue(var_value))
346 data_len += 4
347 elif data_type == DataType.TAB_UINT64:
348 Buffer += pack("=Q", GetIntegerValue(var_value))
349 data_len += 8
350
351 return Buffer
352
353 @staticmethod
354 def PACK_DEFAULT_DATA(defaultstoragename, skuid, var_value):
355 Buffer = ""
356 Buffer += pack("=L", 4+8+8)
357 Buffer += pack("=Q", int(skuid))
358 Buffer += pack("=Q", int(defaultstoragename))
359
360 for item in var_value:
361 Buffer += pack("=B", item)
362
363 Buffer = pack("=L", len(Buffer)+4) + Buffer
364
365 return Buffer
366
367 def GetSkuId(self, skuname):
368 if skuname not in self.SkuIdMap:
369 return None
370 return self.SkuIdMap.get(skuname)[0]
371
372 def GetDefaultStoreId(self, dname):
373 if dname not in self.DefaultStoreMap:
374 return None
375 return self.DefaultStoreMap.get(dname)[0]
376
377 def PACK_DELTA_DATA(self, skuname, defaultstoragename, delta_list):
378 skuid = self.GetSkuId(skuname)
379 defaultstorageid = self.GetDefaultStoreId(defaultstoragename)
380 Buffer = ""
381 Buffer += pack("=L", 4+8+8)
382 Buffer += pack("=Q", int(skuid))
383 Buffer += pack("=Q", int(defaultstorageid))
384 for (delta_offset, value) in delta_list:
385 Buffer += pack("=L", delta_offset)
386 Buffer = Buffer[:-1] + pack("=B", value)
387
388 Buffer = pack("=L", len(Buffer) + 4) + Buffer
389
390 return Buffer
391
392 @staticmethod
393 def AlignData(data, align = 4):
394 mybuffer = data
395 if (len(data) % align) > 0:
396 for i in range(align - (len(data) % align)):
397 mybuffer += pack("=B", 0)
398
399 return mybuffer
400
401 @staticmethod
402 def PACK_VARIABLE_NAME(var_name):
403 Buffer = ""
404 for name_char in var_name.strip("{").strip("}").split(","):
405 Buffer += pack("=B", int(name_char, 16))
406
407 return Buffer