From: Ma, Maurice Date: Wed, 4 Mar 2015 01:03:20 +0000 (+0000) Subject: Add UINT16/32/64 array and DSC include support. X-Git-Tag: edk2-stable201903~10183 X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=commitdiff_plain;h=4c9ed23eb6051ea2cd80cb5c8d9a935964b06b1f Add UINT16/32/64 array and DSC include support. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: "Ma, Maurice" Reviewed-by: "Yao, Jiewen" git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17003 6f19259b-4bc3-4df7-8a09-765794883524 --- diff --git a/IntelFspPkg/Tools/GenCfgOpt.py b/IntelFspPkg/Tools/GenCfgOpt.py index 7e59801879..6b850f6601 100644 --- a/IntelFspPkg/Tools/GenCfgOpt.py +++ b/IntelFspPkg/Tools/GenCfgOpt.py @@ -88,8 +88,206 @@ are permitted provided that the following conditions are met: **/ """ +class CLogicalExpression: + def __init__(self): + self.index = 0 + self.string = '' + + def errExit(self, err = ''): + print "ERROR: Express parsing for:" + print " %s" % self.string + print " %s^" % (' ' * self.index) + if err: + print "INFO : %s" % err + raise SystemExit + + def getNonNumber (self, n1, n2): + if not n1.isdigit(): + return n1 + if not n2.isdigit(): + return n2 + return None + + def getCurr(self, lens = 1): + try: + if lens == -1: + return self.string[self.index :] + else: + if self.index + lens > len(self.string): + lens = len(self.string) - self.index + return self.string[self.index : self.index + lens] + except Exception: + return '' + + def isLast(self): + return self.index == len(self.string) + + def moveNext(self, len = 1): + self.index += len + + def skipSpace(self): + while not self.isLast(): + if self.getCurr() in ' \t': + self.moveNext() + else: + return + + def normNumber (self, val): + return True if val else False + + def getNumber(self, var): + var = var.strip() + if re.match('^0x[a-fA-F0-9]+$', var): + value = int(var, 16) + elif re.match('^[+-]?\d+$', var): + value = int(var, 10) + else: + value = None + return value + + def parseValue(self): + self.skipSpace() + var = '' + while not self.isLast(): + char = self.getCurr() + if re.match('^[\w.]', char): + var += char + self.moveNext() + else: + break + val = self.getNumber(var) + if val is None: + value = var + else: + value = "%d" % val + return value + + def parseSingleOp(self): + self.skipSpace() + if re.match('^NOT\W', self.getCurr(-1)): + self.moveNext(3) + op = self.parseBrace() + val = self.getNumber (op) + if val is None: + self.errExit ("'%s' is not a number" % op) + return "%d" % (not self.normNumber(int(op))) + else: + return self.parseValue() + + def parseBrace(self): + self.skipSpace() + char = self.getCurr() + if char == '(': + self.moveNext() + value = self.parseExpr() + self.skipSpace() + if self.getCurr() != ')': + self.errExit ("Expecting closing brace or operator") + self.moveNext() + return value + else: + value = self.parseSingleOp() + return value + + def parseCompare(self): + value = self.parseBrace() + while True: + self.skipSpace() + char = self.getCurr() + if char in ['<', '>']: + self.moveNext() + next = self.getCurr() + if next == '=': + op = char + next + self.moveNext() + else: + op = char + result = self.parseBrace() + test = self.getNonNumber(result, value) + if test is None: + value = "%d" % self.normNumber(eval (value + op + result)) + else: + self.errExit ("'%s' is not a valid number for comparision" % test) + elif char in ['=', '!']: + op = self.getCurr(2) + if op in ['==', '!=']: + self.moveNext(2) + result = self.parseBrace() + test = self.getNonNumber(result, value) + if test is None: + value = "%d" % self.normNumber((eval (value + op + result))) + else: + value = "%d" % self.normNumber(eval ("'" + value + "'" + op + "'" + result + "'")) + else: + break + else: + break + return value + + def parseAnd(self): + value = self.parseCompare() + while True: + self.skipSpace() + if re.match('^AND\W', self.getCurr(-1)): + self.moveNext(3) + result = self.parseCompare() + test = self.getNonNumber(result, value) + if test is None: + value = "%d" % self.normNumber(int(value) & int(result)) + else: + self.errExit ("'%s' is not a valid op number for AND" % test) + else: + break + return value + + def parseOrXor(self): + value = self.parseAnd() + op = None + while True: + self.skipSpace() + op = None + if re.match('^XOR\W', self.getCurr(-1)): + self.moveNext(3) + op = '^' + elif re.match('^OR\W', self.getCurr(-1)): + self.moveNext(2) + op = '|' + else: + break + if op: + result = self.parseAnd() + test = self.getNonNumber(result, value) + if test is None: + value = "%d" % self.normNumber(eval (value + op + result)) + else: + self.errExit ("'%s' is not a valid op number for XOR/OR" % test) + return value + + def parseExpr(self): + return self.parseOrXor() + + def getResult(self): + value = self.parseExpr() + self.skipSpace() + if not self.isLast(): + self.errExit ("Unexpected character found '%s'" % self.getCurr()) + test = self.getNumber(value) + if test is None: + self.errExit ("Result '%s' is not a number" % value) + return int(value) + + def evaluateExpress (self, Expr): + self.index = 0 + self.string = Expr + if self.getResult(): + Result = True + else: + Result = False + return Result + class CGenCfgOpt: def __init__(self): + self.Debug = False self.Error = '' self._GlobalDataDef = """ @@ -139,12 +337,71 @@ EndList if Match: self._MacroDict[Match.group(1)] = '' if len(self._MacroDict) == 0: - self.Error = "Invalid MACRO arguments" Error = 1 else: Error = 0 + if self.Debug: + print "INFO : Macro dictionary:" + for Each in self._MacroDict: + print " $(%s) = [ %s ]" % (Each , self._MacroDict[Each]) return Error + def EvaulateIfdef (self, Macro): + Result = Macro in self._MacroDict + if self.Debug: + print "INFO : Eval Ifdef [%s] : %s" % (Macro, Result) + return Result + + def ExpandMacros (self, Input): + Line = Input + Match = re.findall("\$\(\w+\)", Input) + if Match: + for Each in Match: + Variable = Each[2:-1] + if Variable in self._MacroDict: + Line = Line.replace(Each, self._MacroDict[Variable]) + else: + if self.Debug: + print "WARN : %s is not defined" % Each + Line = Line.replace(Each, Each[2:-1]) + return Line + + def EvaluateExpress (self, Expr): + ExpExpr = self.ExpandMacros(Expr) + LogExpr = CLogicalExpression() + Result = LogExpr.evaluateExpress (ExpExpr) + if self.Debug: + print "INFO : Eval Express [%s] : %s" % (Expr, Result) + return Result + + def FormatListValue(self, ConfigDict): + Struct = ConfigDict['struct'] + if Struct not in ['UINT8','UINT16','UINT32','UINT64']: + return + + dataarray = [] + binlist = ConfigDict['value'][1:-1].split(',') + for each in binlist: + each = each.strip() + if each.startswith('0x'): + value = int(each, 16) + else: + value = int(each) + dataarray.append(value) + + unit = int(Struct[4:]) / 8 + if int(ConfigDict['length']) != unit * len(dataarray): + raise Exception("Array size is not proper for '%s' !" % ConfigDict['cname']) + + bytearray = [] + for each in dataarray: + value = each + for loop in xrange(unit): + bytearray.append("0x%02X" % (value & 0xFF)) + value = value >> 8 + newvalue = '{' + ','.join(bytearray) + '}' + ConfigDict['value'] = newvalue + return "" def ParseDscFile (self, DscFile, FvDir): self._CfgItemList = [] @@ -158,20 +415,19 @@ EndList IsVpdSect = False Found = False - IfStack = [True] + IfStack = [] ElifStack = [] Error = 0 + ConfigDict = {} DscFd = open(DscFile, "r") DscLines = DscFd.readlines() DscFd.close() - ConfigDict = {} - - for DscLine in DscLines: - Handle = False - DscLine = DscLine.strip() - Match = re.match("^\[(.+)\]", DscLine) + while len(DscLines): + DscLine = DscLines.pop(0).strip() + Handle = False + Match = re.match("^\[(.+)\]", DscLine) if Match is not None: if Match.group(1).lower() == "Defines".lower(): IsDefSect = True @@ -210,66 +466,78 @@ EndList IsVpdSect = False else: if IsDefSect or IsUpdSect or IsVpdSect: - if DscLine == "!else": - IfStack[-1] = not IfStack[-1] - elif DscLine == "!endif": - IfStack.pop() - Level = ElifStack.pop() - while Level > 0: + if re.match("^!else($|\s+#.+)", DscLine): + if IfStack: + IfStack[-1] = not IfStack[-1] + else: + print("ERROR: No paired '!if' found for '!else' for line '%s'" % DscLine) + raise SystemExit + elif re.match("^!endif($|\s+#.+)", DscLine): + if IfStack: IfStack.pop() - Level = Level - 1 + Level = ElifStack.pop() + if Level > 0: + del IfStack[-Level:] + else: + print("ERROR: No paired '!if' found for '!endif' for line '%s'" % DscLine) + raise SystemExit else: Result = False - Match = re.match("!(ifdef|ifndef)\s+\$\((\w+)\)", DscLine) - if Match is not None: - if Match.group(2) in self._MacroDict: - if Match.group(1) == 'ifdef': - Result = True - else: - if Match.group(1) == 'ifndef': - Result = True - ElifStack.append(0) + Match = re.match("!(ifdef|ifndef)\s+(.+)", DscLine) + if Match: + Result = self.EvaulateIfdef (Match.group(2)) + if Match.group(1) == 'ifndef': + Result = not Result IfStack.append(Result) + ElifStack.append(0) else: - Match = re.match("!(if|elseif)\s+\$\\((\w+)\)\s*==\s*(\w+|\$\(\w+\))", DscLine) - if Match is not None: - if Match.group(2) in self._MacroDict: - MacroName = self._MacroDict[Match.group(2)] - else: - MacroName = '' - Value = Match.group(3) - if Value.startswith('$'): - if Value[2:-1] in self._MacroDict: - Value = self._MacroDict[Value[2:-1]] - else: - Value = '' - if MacroName == Value: - Result = True + Match = re.match("!(if|elseif)\s+(.+)", DscLine) + if Match: + Result = self.EvaluateExpress(Match.group(2)) if Match.group(1) == "if": ElifStack.append(0) IfStack.append(Result) else: #elseif - IfStack[-1] = not IfStack[-1] - IfStack.append(Result) - ElifStack[-1] = ElifStack[-1] + 1 + if IfStack: + IfStack[-1] = not IfStack[-1] + IfStack.append(Result) + ElifStack[-1] = ElifStack[-1] + 1 + else: + print("ERROR: No paired '!if' found for '!elif' for line '%s'" % DscLine) + raise SystemExit else: - if len(DscLine) > 0 and DscLine[0] == '!': - # - # Current it can only handle build switch. - # It does not support INF file in included dsc. - # + if IfStack: + Handle = reduce(lambda x,y: x and y, IfStack) else: - if reduce(lambda x,y: x and y, IfStack): - Handle = True - + Handle = True + if Handle: + Match = re.match("!include\s+(.+)", DscLine) + if Match: + IncludeFilePath = Match.group(1) + IncludeFilePath = self.ExpandMacros(IncludeFilePath) + try: + IncludeDsc = open(IncludeFilePath, "r") + except: + print("ERROR: Cannot open file '%s'" % IncludeFilePath) + raise SystemExit + NewDscLines = IncludeDsc.readlines() + IncludeDsc.close() + DscLines = NewDscLines + DscLines + else: + if DscLine.startswith('!'): + print("ERROR: Unrecoginized directive for line '%s'" % DscLine) + raise SystemExit + if not Handle: continue if IsDefSect: #DEFINE UPD_TOOL_GUID = 8C3D856A-9BE6-468E-850A-24F7A8D38E09 - Match = re.match("^\s*(?:DEFINE\s+)*(\w+)\s*=\s*([-\w]+)", DscLine) + Match = re.match("^\s*(?:DEFINE\s+)*(\w+)\s*=\s*([-.\w]+)", DscLine) if Match: self._MacroDict[Match.group(1)] = Match.group(2) + if self.Debug: + print "INFO : DEFINE %s = [ %s ]" % (Match.group(1), Match.group(2)) else: Match = re.match("^\s*#\s+!(BSF|HDR)\s+(.+)", DscLine) if Match: @@ -338,7 +606,11 @@ EndList if Match: if Match.group(1) in self._MacroDict: Value = self._MacroDict[Match.group(1)] + ConfigDict['value'] = Value + if (len(Value) > 0) and (Value[0] == '{'): + Value = self.FormatListValue(ConfigDict) + if ConfigDict['name'] == '': # Clear BSF specific items ConfigDict['help'] = '' @@ -502,26 +774,29 @@ EndList TxtFd.close() return 0 - def CreateField (self, Name, Length, Offset, Struct): + def CreateField (self, Item, Name, Length, Offset, Struct): PosName = 28 PosComment = 30 IsArray = False - if Length == 1: - Type = "UINT8" - elif Length == 2: - Type = "UINT16" - elif Length == 4: - Type = "UINT32" - elif Length == 8: - Type = "UINT64" + if Length in [1,2,4,8]: + Type = "UINT%d" % (Length * 8) else: + IsArray = True + Type = "UINT8" + + if Item['value'].startswith('{'): Type = "UINT8" IsArray = True if Struct != '': - IsArray = False Type = Struct + if Struct in ['UINT8','UINT16','UINT32','UINT64']: + IsArray = True + Unit = int(Type[4:]) / 8 + Length = Length / Unit + else: + IsArray = False if IsArray: Name = Name + '[%d]' % Length @@ -644,12 +919,12 @@ EndList NextVisible = True Name = "Reserved" + Region[0] + "pdSpace%d" % ResvIdx ResvIdx = ResvIdx + 1 - HeaderFd.write(self.CreateField (Name, Item["offset"] - ResvOffset, ResvOffset, '')) + HeaderFd.write(self.CreateField (Item, Name, Item["offset"] - ResvOffset, ResvOffset, '')) if Offset < Item["offset"]: if IsInternal or LastVisible: Name = "Unused" + Region[0] + "pdSpace%d" % SpaceIdx - LineBuffer.append(self.CreateField (Name, Item["offset"] - Offset, Offset, '')) + LineBuffer.append(self.CreateField (Item, Name, Item["offset"] - Offset, Offset, '')) SpaceIdx = SpaceIdx + 1 Offset = Item["offset"] @@ -665,7 +940,7 @@ EndList for Each in LineBuffer: HeaderFd.write (Each) LineBuffer = [] - HeaderFd.write(self.CreateField (Item["cname"], Item["length"], Item["offset"], Item['struct'])) + HeaderFd.write(self.CreateField (Item, Item["cname"], Item["length"], Item["offset"], Item['struct'])) HeaderFd.write("} " + Region[0] + "PD_DATA_REGION;\n\n") HeaderFd.write("#pragma pack()\n\n") @@ -846,7 +1121,6 @@ def Main(): print "ERROR: %s !" % GenCfgOpt.Error return 5 - if GenCfgOpt.UpdateVpdSizeField() != 0: print "ERROR: %s !" % GenCfgOpt.Error return 6