1## @ PatchBinFv.py
2#
3# Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
4# SPDX-License-Identifier: BSD-2-Clause-Patent
5#
6##
7
8import os
9import re
10import sys
11import time
12import shutil
13import struct
14import binascii
15from   ctypes import *
16
17class FileChecker:
18    def __init__(self):
19        self.SyncSectionList = ["PatchPcd"]
20        self.FvName = ""
21        self.target = ""
22        self.sourceRoot = ""
23        self.reportFile = ""
24        self.InfPcdList = []
25
26    def GetSectionName(self, line):
27        splitLine = line[1:-1].split(".")
28        return splitLine[0]
29
30    def IsSyncSection(self, line):
31        name = self.GetSectionName(line)
32        for sectionName in self.SyncSectionList:
33            if (cmp (sectionName, name) == 0) :
34                return True
35        return False
36
37    def PrintPcdList(self, pcdList):
38        for pcd in pcdList:
39            print "PCD: " + pcd[0] + "|" + pcd[1] + "|" + pcd[2] + " <== " + pcd[3] + "(" + pcd[4] + ")"
40
41    def GetInfFileGuid(self, fileName):
42        guid = ""
43        try :
44            file = open(fileName)
45        except Exception:
46            print "fail to open " + fileName
47            return
48        try:
49            while 1:
50                line = file.readline()
51                if not line:
52                    break
53
54                newline = line[:-1]
55
56                if cmp (line[:11], "  FILE_GUID") == 0:
57                    splitLine = line.split("=")
58                    templine = splitLine[1]
59                    guid = templine[1:1+36]
60        finally:
61            file.close()
62        return guid
63
64    def ParseInfFile(self, fileName):
65        SyncToDest = False
66        try :
67            file = open(fileName)
68        except Exception:
69            print "fail to open " + fileName
70            return
71        try:
72            while 1:
73                line = file.readline()
74                if not line:
75                    break
76
77                newline = line[:-1]
78
79                if cmp (line[0], "#") == 0:
80                    continue
81
82
83                if cmp (line[0], "[") == 0:
84                    SyncToDest = self.IsSyncSection(line)
85                    PatchOffset = False
86
87                if (cmp (self.GetSectionName(line), "PatchPcd") == 0) :
88                    PatchOffset = True
89                    continue
90
91                if SyncToDest == True :
92                    line = line.strip()
93                    if (cmp (line, "") == 0) :
94                        continue
95                    if (cmp (line[0], "#") == 0) :
96                        continue
97
98                    splitLine = line.split(" ")
99                    line = splitLine[0]
100
101                    splitLine = line.split("|")
102
103                    self.InfPcdList.append([splitLine[0], splitLine[1], splitLine[2], "", ""])
104
105        finally:
106            file.close()
107        return
108
109    def ProcessFvInf(self, fvName):
110        sourceFileName = os.path.join(self.sourceRoot,fvName,self.target,fvName+".inf")
111        print "\nprocessing - " + sourceFileName
112        fileGuid = self.GetInfFileGuid (sourceFileName)
113        print "FV NAME GUID - " + fileGuid
114
115        self.InfPcdList = []
116        self.ParseInfFile(sourceFileName)
117
118        self.InfPcdList.sort()
119
120        #self.PrintPcdList(self.InfPcdList)
121
122        try :
123            file = open(self.reportFile)
124        except Exception:
125            print "fail to open " + self.reportFile
126            return
127        try:
128            for pcd in self.InfPcdList:
129                file.seek(0)
130                print "checking - " + pcd[0]
131                ValuePair = self.GetPcdFromReport (file, pcd[0])
132                pcd[3] = ValuePair[0]
133                pcd[4] = ValuePair[1]
134        finally:
135            file.close()
136
137        self.PrintPcdList(self.InfPcdList)
138
139    def PatchFv(self, fvName):
140        sourceFileName = os.path.join(self.sourceRoot,fvName,self.target,fvName+".Fv")
141        print "patching - " + sourceFileName
142
143        try :
144            file = open(sourceFileName, "rb")
145        except Exception:
146            print "fail to open " + sourceFileName
147            return
148        try:
149            buffer = file.read()
150            data = bytearray(buffer)
151            file.close()
152
153            for pcd in self.InfPcdList:
154                offset = int(pcd[2], 16)
155                if (cmp (pcd[4], "BOOLEAN") == 0) or (cmp (pcd[4], "UINT8") == 0):
156                    b = struct.pack("B", int(pcd[3],16))
157                    print "  [" + hex(offset) + "] " + binascii.hexlify(data[offset:offset+1]) + " <= " + binascii.hexlify(b)
158                    data[offset:offset+1] = b
159                elif (cmp (pcd[4], "UINT16") == 0):
160                    h = struct.pack("H", int(pcd[3],16))
161                    print "  [" + hex(offset) + "] " + binascii.hexlify(data[offset:offset+2]) + " <= " + binascii.hexlify(h)
162                    data[offset:offset+2] = h
163                elif (cmp (pcd[4], "UINT32") == 0):
164                    l = struct.pack("I", int(pcd[3],16))
165                    print "  [" + hex(offset) + "] " + binascii.hexlify(data[offset:offset+4]) + " <= " + binascii.hexlify(l)
166                    data[offset:offset+4] = l
167                elif (cmp (pcd[4], "UINT64") == 0):
168                    q = struct.pack("Q", int(pcd[3],16))
169                    print "  [" + hex(offset) + "] " + binascii.hexlify(data[offset:offset+8]) + " <= " + binascii.hexlify(q)
170                    data[offset:offset+8] = q
171            file = open(sourceFileName, "wb")
172            file.write(data)
173        finally:
174            file.close()
175
176    def GetPcdFromReport(self, file, pcd):
177        FoundPkg = False
178        pcdSplit = pcd.split(".")
179        TargetPkg = pcdSplit[0]
180        TargetPcd = pcdSplit[1]
181        while 1:
182            line = file.readline()
183            if not line:
184                break
185
186            newline = line[:-1]
187
188            if (cmp (newline, TargetPkg) == 0):
189                FoundPkg = True
190                continue
191
192            if (cmp (newline, "") == 0) or ((cmp (newline[0], " ") != 0) and (cmp (newline[0], "0") != 0)):
193                FoundPkg = False
194
195            if (FoundPkg == True) :
196                newline = newline.strip()
197                splitLine = newline.split(" ", 2)
198                if (cmp (splitLine[0], "*F") == 0) or (cmp (splitLine[0], "*P") == 0):
199                    if (cmp (splitLine[1], TargetPcd) == 0):
200                        print "found - " + TargetPkg + "." + TargetPcd
201
202                        splitLine = splitLine[2].strip()[1:].strip().split(" ", 1)
203                        if (cmp (splitLine[0], "FIXED") == 0) or (cmp (splitLine[0], "PATCH") == 0):
204                            SplitLine = splitLine[1].strip()[1:].split(")", 1)
205                            Type = SplitLine[0]
206                            Value = SplitLine[1].strip()[1:].strip().split()[0]
207                            print "  Type - (" + Type + "), Value - (" + Value + ")"
208                            return [Value, Type]
209        return ["", ""]
210
211def main():
212    global FileChecker
213
214    fileChecker = FileChecker()
215
216    if (len(sys.argv) != 5) :
217        print "usage: PatchBinFv <Target> <SourceRoot> <ReportFile> <FvName>"
218        return 0
219
220    fileChecker.target = sys.argv[1]
221    fileChecker.sourceRoot = sys.argv[2]
222    fileChecker.reportFile = sys.argv[3]
223    fileChecker.FvName = sys.argv[4]
224
225    fileChecker.ProcessFvInf (fileChecker.FvName)
226    fileChecker.PatchFv (fileChecker.FvName)
227
228if __name__ == '__main__':
229    sys.exit(main())
230