[PATCH i-g-t v2 3/6] tools/intel-gfx-fw-info: Embed fw decoding

Lucas De Marchi lucas.demarchi at intel.com
Wed Aug 21 18:17:42 UTC 2024


On Wed, Aug 21, 2024 at 02:06:30PM GMT, Gustavo Sousa wrote:
>Quoting Lucas De Marchi (2024-08-20 20:29:25-03:00)
>>Use a factory class method to decide what class to use depending on the
>>magic and embed the calls to cstruct in each of them. Main motivation is
>>that in future the decode method will need to seek the binary as it
>>can't really know the version just checking the beginning of the file.
>>
>>For now, keep the open/close of the file in the main function, but
>>eventually can be migrated as well.
>>
>>Signed-off-by: Lucas De Marchi <lucas.demarchi at intel.com>
>>---
>> tools/intel-gfx-fw-info | 73 ++++++++++++++++++++++++++++-------------
>> 1 file changed, 51 insertions(+), 22 deletions(-)
>>
>>diff --git a/tools/intel-gfx-fw-info b/tools/intel-gfx-fw-info
>>index 3105144b7..0f1da8bff 100755
>>--- a/tools/intel-gfx-fw-info
>>+++ b/tools/intel-gfx-fw-info
>>@@ -105,8 +105,38 @@ def FIELD_GET(mask: int, value: int) -> int:
>>
>>
>> class Fw(abc.ABC):
>>-    def __init__(self, fw):
>>-        self.fw = fw
>>+    def __init__(self, cparser, f):
>>+        self.f = f
>>+        self.cparser = cparser
>>+        self.fw = None
>>+
>>+    def checksum(self):
>>+        self.f.seek(0, 0)
>>+        return hashlib.sha256(self.f.read()).hexdigest()
>>+
>>+    def dump(self, **kw):
>>+        cstruct.dumpstruct(self.fw, kw)
>
>s/kw/**kw/
>
>>+
>>+    @classmethod
>>+    def create(cls, f):
>>+        cparser = cstruct.cstruct()
>>+        cparser.load(CDEF)
>>+
>>+        magic = cparser.magic(f).data
>>+        default = None
>>+
>>+        for s in cls.__subclasses__():
>>+            if s.MAGIC is None:
>>+                default = s
>>+            elif s.MAGIC == magic:
>>+                f.seek(0, 0)
>>+                return s(cparser, f)
>>+
>>+        if default:
>>+            f.seek(0, 0)
>
>Is this seek() necessary? Looks like functions that use f already rewind
>before using f.

yeah... I went back and forth between leaving it inside or outside.
When we add support for GSC we may want it outside since GSC basically
adds some headers before the  gsc_cpd_header_v2 that is used by HuC.

I will remove the seek() from here for now.

>
>>+            return default(cparser, f)
>
>I believe a cleaner way of doing this is to have a single "constructor"
>variable so that we have a single point of instantiation. Something
>like:
>
>    constructor = None
>
>    for s in cls.__subclasses__():
>        if s.MAGIC is None:
>            constructor = s
>        elif s.MAGIC == magic:
>            constructor = s
>            break
>
>    if constructor:
>        f.seek(0, 0)
>        return constructor(cparser, f)

yeah, better. I will update the patch with that.

>
>>+
>>+        return None
>>
>>     @abc.abstractmethod
>>     def decode(self):
>>@@ -114,8 +144,13 @@ class Fw(abc.ABC):
>>
>>
>> class FwCss(Fw):
>>+    MAGIC = None
>>+
>>     def decode(self):
>>-        data = []
>>+        self.f.seek(0, 0)
>>+        self.fw = self.cparser.uc_css_header(self.f)
>>+
>>+        data = ["header-type: CSS"]
>>
>>         CSS_SW_VERSION_UC_MAJOR = 0xFF << 16
>>         CSS_SW_VERSION_UC_MINOR = 0xFF << 8
>>@@ -137,8 +172,13 @@ class FwCss(Fw):
>>
>>
>> class FwGsc(Fw):
>>+    MAGIC = b"$CPD"
>>+
>>     def decode(self):
>>-        data = []
>>+        self.f.seek(0, 0)
>>+        self.fw = self.cparser.uc_huc_gsc_header(self.f)
>>+
>>+        data = ["header-type: GSC"]
>>
>>         HUC_GSC_MINOR_VER_HI_MASK = 0xFF << 16
>>         HUC_GSC_MAJOR_VER_HI_MASK = 0xFF
>>@@ -167,40 +207,29 @@ def parse_args(argv: typing.List[str]) -> argparse.Namespace:
>>     return parser.parse_args(argv)
>>
>>
>>-def calculate_checksum(f: typing.BinaryIO) -> str:
>>-    return hashlib.sha256(f.read()).hexdigest()
>>-
>>-
>> def main(argv: typing.List[str]) -> int:
>>     args = parse_args(argv)
>>
>>-    cparser = cstruct.cstruct()
>>-    cparser.load(CDEF)
>>-
>>     checksum = None
>>
>>     try:
>>         with open(args.filename, mode="rb") as f:
>>-            magic = cparser.magic(f)
>>-            f.seek(0, 0)
>>-            if magic.data == b"$CPD":
>>-                fw = FwGsc(cparser.uc_huc_gsc_header(f))
>>-            else:
>>-                fw = FwCss(cparser.uc_css_header(f))
>>+            fw = Fw.create(f)
>>+            if not fw:
>>+                logging.fatal("Unknown firmware type in '{args.filename}'")
>
>Note that this doesn't cause the script to abort...

there is a sys.exit(1) squashed in the wrong patch (5). I will bring it
here.

Thanks
Lucas De Marchi

>
>>
>>+            decoded_data = fw.decode()
>
>...meaning that we crash here if fw is None.
>
>--
>Gustavo Sousa
>
>>             if args.checksum:
>>-                f.seek(0, 0)
>>-                checksum = calculate_checksum(f)
>>-
>>+                checksum = fw.checksum()
>>     except FileNotFoundError as e:
>>         logging.fatal(e)
>>         return 1
>>
>>-    print(*fw.decode(), sep="\n")
>>+    print(*decoded_data, sep="\n")
>>
>>     if args.raw:
>>         print("raw dump:", end="")
>>-        cstruct.dumpstruct(fw.fw, color=sys.stdout.isatty())
>>+        fw.dump(color=sys.stdout.isatty())
>>
>>     if checksum:
>>         print(f"checksum: {checksum}")
>>--
>>2.43.0
>>


More information about the igt-dev mailing list