From 305e667ef70a3e87d17c4d88f0aea7e1def1274c Mon Sep 17 00:00:00 2001 From: Johann Chang Date: Thu, 10 Nov 2022 17:29:10 +0800 Subject: [PATCH] Add intel-ipu-fw-info as a standalone tool --- tools/intel-ipu-fw-info/.gitignore | 264 ++++++++++++++++++ tools/intel-ipu-fw-info/README.md | 15 + .../intel_ipu_fw_info/__about__.py | 1 + .../intel_ipu_fw_info/__init__.py | 3 + .../intel_ipu_fw_info/cli.py | 28 ++ .../intel_ipu_fw_info/key.py | 127 +++++++++ .../intel_ipu_fw_info/parser.py | 199 +++++++++++++ .../intel_ipu_fw_info/spec.py | 105 +++++++ tools/intel-ipu-fw-info/pyproject.toml | 53 ++++ tools/intel-ipu-fw-info/tests/__init__.py | 0 10 files changed, 795 insertions(+) create mode 100644 tools/intel-ipu-fw-info/.gitignore create mode 100644 tools/intel-ipu-fw-info/README.md create mode 100644 tools/intel-ipu-fw-info/intel_ipu_fw_info/__about__.py create mode 100644 tools/intel-ipu-fw-info/intel_ipu_fw_info/__init__.py create mode 100644 tools/intel-ipu-fw-info/intel_ipu_fw_info/cli.py create mode 100644 tools/intel-ipu-fw-info/intel_ipu_fw_info/key.py create mode 100644 tools/intel-ipu-fw-info/intel_ipu_fw_info/parser.py create mode 100644 tools/intel-ipu-fw-info/intel_ipu_fw_info/spec.py create mode 100644 tools/intel-ipu-fw-info/pyproject.toml create mode 100644 tools/intel-ipu-fw-info/tests/__init__.py diff --git a/tools/intel-ipu-fw-info/.gitignore b/tools/intel-ipu-fw-info/.gitignore new file mode 100644 index 0000000..675912b --- /dev/null +++ b/tools/intel-ipu-fw-info/.gitignore @@ -0,0 +1,264 @@ +# Python { +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ +# } Python + +# Vim { +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ +# } Vim + +# JetBrains { +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser +# } JetBrains diff --git a/tools/intel-ipu-fw-info/README.md b/tools/intel-ipu-fw-info/README.md new file mode 100644 index 0000000..6fc87fd --- /dev/null +++ b/tools/intel-ipu-fw-info/README.md @@ -0,0 +1,15 @@ +# intel-ipu-fw-info + +## Installation + +``` +pip install --editable . +``` + +## Usage + +``` +intel-ipu-fw-info +``` + +See `intel-ipu-fw-info -h` for details diff --git a/tools/intel-ipu-fw-info/intel_ipu_fw_info/__about__.py b/tools/intel-ipu-fw-info/intel_ipu_fw_info/__about__.py new file mode 100644 index 0000000..1f356cc --- /dev/null +++ b/tools/intel-ipu-fw-info/intel_ipu_fw_info/__about__.py @@ -0,0 +1 @@ +__version__ = '1.0.0' diff --git a/tools/intel-ipu-fw-info/intel_ipu_fw_info/__init__.py b/tools/intel-ipu-fw-info/intel_ipu_fw_info/__init__.py new file mode 100644 index 0000000..54fc8a9 --- /dev/null +++ b/tools/intel-ipu-fw-info/intel_ipu_fw_info/__init__.py @@ -0,0 +1,3 @@ +from .key import Key +from .parser import get_firmware_info +from .spec import FirmwareInfo diff --git a/tools/intel-ipu-fw-info/intel_ipu_fw_info/cli.py b/tools/intel-ipu-fw-info/intel_ipu_fw_info/cli.py new file mode 100644 index 0000000..29acc3b --- /dev/null +++ b/tools/intel-ipu-fw-info/intel_ipu_fw_info/cli.py @@ -0,0 +1,28 @@ +import argparse +import dataclasses +import json +import os +import pathlib +from typing import BinaryIO + +from .parser import ByteEncoder, FirmwareInfo, get_cse, get_firmware_info +from .spec import CSE + + +def parse_args() -> argparse.Namespace: + parser: argparse.ArgumentParser = argparse.ArgumentParser() + parser.add_argument('--full', action='store_true', help=f'show full info') + parser.add_argument('firmware_path', metavar='', type=pathlib.Path, help='path to the firmware') + return parser.parse_args() + + +def main() -> int: + args: argparse.Namespace = parse_args() + + f: BinaryIO + with open(args.firmware_path, 'rb') as f: + firmware: bytes = f.read() + info: CSE | FirmwareInfo = get_cse(firmware) if args.full else get_firmware_info(firmware) + print(json.dumps(dataclasses.asdict(info), indent=2, cls=ByteEncoder)) + + return os.EX_OK diff --git a/tools/intel-ipu-fw-info/intel_ipu_fw_info/key.py b/tools/intel-ipu-fw-info/intel_ipu_fw_info/key.py new file mode 100644 index 0000000..f7b99ad --- /dev/null +++ b/tools/intel-ipu-fw-info/intel_ipu_fw_info/key.py @@ -0,0 +1,127 @@ +import enum + + +class Key(enum.Enum): + UNKNOWN: 'Key' = None + JSL_TEST: 'Key' = bytes([ + 0xdf, 0xf4, 0x1c, 0xfd, 0x41, 0x1b, 0x66, 0x77, 0x76, 0x0d, 0x64, 0xcc, 0x9e, 0x28, 0x07, 0xbc, + 0x2d, 0xd1, 0x84, 0x8c, 0x55, 0xe2, 0x58, 0x31, 0xd7, 0x86, 0x69, 0x7a, 0x95, 0x56, 0x1a, 0xb6, + 0x41, 0x67, 0x7d, 0x3c, 0x56, 0x1b, 0x68, 0x5c, 0x17, 0x95, 0xfe, 0x21, 0xcd, 0xbd, 0x86, 0x26, + 0x27, 0x36, 0xac, 0xdc, 0x67, 0x68, 0x29, 0x11, 0xbd, 0xa4, 0xe9, 0xf9, 0x2b, 0x33, 0xe8, 0xb1, + 0x9e, 0xe2, 0x67, 0xe2, 0x92, 0x31, 0x13, 0xaa, 0x37, 0xf8, 0x70, 0x45, 0xed, 0x02, 0x37, 0x48, + 0x0c, 0x6c, 0x6d, 0x81, 0x61, 0xf2, 0x7d, 0xe8, 0x6e, 0x3f, 0x6e, 0xde, 0x6c, 0xcf, 0xe7, 0xa5, + 0x1b, 0xef, 0x4d, 0xcd, 0xfc, 0x61, 0x0f, 0x19, 0x1a, 0xa8, 0xbe, 0xb8, 0xee, 0x4e, 0x43, 0x3e, + 0x16, 0x96, 0xa9, 0xb7, 0xd1, 0x02, 0x8b, 0x2b, 0x5a, 0xb7, 0x67, 0x8a, 0xe2, 0x14, 0x47, 0xcf, + 0x24, 0x9c, 0x0c, 0xb7, 0x26, 0x44, 0xcc, 0xf8, 0x8f, 0xd7, 0x25, 0xbc, 0xac, 0xb6, 0x31, 0xfe, + 0x25, 0xf1, 0x9a, 0x91, 0xa6, 0x19, 0x6e, 0x26, 0x9c, 0xf6, 0x6b, 0x43, 0x77, 0x2a, 0x28, 0x67, + 0x65, 0x24, 0xf9, 0x31, 0x53, 0xe1, 0x06, 0xd4, 0x1a, 0x2f, 0x30, 0x5d, 0x40, 0x8b, 0xdf, 0xe0, + 0xb9, 0xf0, 0xc5, 0x9e, 0x6d, 0xd3, 0x41, 0x12, 0x10, 0x94, 0x8a, 0xbf, 0x7f, 0x93, 0x42, 0x89, + 0x6e, 0xc5, 0xba, 0x85, 0xb9, 0xa2, 0xdd, 0xd8, 0x22, 0x6a, 0x6f, 0x2a, 0x7d, 0x10, 0x4d, 0xd6, + 0xe7, 0x13, 0xc7, 0x13, 0xb1, 0xfb, 0x7b, 0x90, 0xe6, 0x42, 0x80, 0x42, 0xe1, 0xd0, 0xc8, 0xfa, + 0x23, 0x09, 0x9e, 0xc9, 0x9a, 0x38, 0x2a, 0x10, 0x9a, 0x45, 0x44, 0x63, 0xe8, 0x88, 0x41, 0xab, + 0x26, 0xb7, 0x01, 0x98, 0xe8, 0x22, 0xc3, 0x23, 0x90, 0xfb, 0x11, 0x11, 0x65, 0xf0, 0xea, 0x9f, + ]) + JSL_PRODUCTION: 'Key' = bytes([ + 0xd1, 0x49, 0xdd, 0x52, 0xbc, 0x95, 0x97, 0xde, 0xc1, 0x6b, 0x51, 0x60, 0x41, 0x59, 0x05, 0x05, + 0xe7, 0x16, 0xc7, 0x3b, 0x98, 0xeb, 0x0c, 0x09, 0xa3, 0x52, 0x6c, 0x67, 0xc8, 0x66, 0x26, 0x90, + 0x13, 0x6b, 0x06, 0xaf, 0x91, 0x5c, 0x77, 0x7f, 0x0f, 0xbd, 0x54, 0xaf, 0xca, 0xaf, 0xaf, 0xf7, + 0xca, 0xcc, 0x7e, 0xcb, 0x59, 0xea, 0xc1, 0xe1, 0x01, 0x65, 0x9b, 0x0b, 0x21, 0xc0, 0x6d, 0xd7, + 0x5f, 0x31, 0x52, 0x62, 0xce, 0xd1, 0x97, 0x22, 0x17, 0x91, 0xcf, 0xc4, 0x99, 0xd1, 0xb2, 0xa7, + 0x41, 0xd4, 0xe3, 0x7d, 0x71, 0x9d, 0x22, 0xc1, 0x98, 0x1d, 0x3e, 0x42, 0xc3, 0xf4, 0x88, 0x98, + 0xa8, 0x9a, 0xe5, 0xc2, 0xd3, 0x57, 0xd4, 0xcc, 0x1d, 0xaa, 0x67, 0x3a, 0xdf, 0x12, 0x4a, 0x3b, + 0xda, 0xb0, 0x7c, 0xe8, 0x78, 0x5a, 0x9f, 0x9d, 0x7b, 0x82, 0x25, 0xbd, 0x9d, 0xc5, 0x93, 0x0d, + 0xa1, 0xa9, 0xb9, 0xbe, 0xc2, 0xa4, 0x66, 0x7e, 0x8b, 0xac, 0x84, 0x5d, 0xcf, 0x17, 0x6e, 0xe2, + 0x66, 0x79, 0x96, 0xec, 0x2e, 0xdd, 0xc6, 0xaf, 0x5d, 0xba, 0xd0, 0x33, 0x2a, 0xdf, 0x3f, 0xfc, + 0x5b, 0xf4, 0x10, 0x27, 0x59, 0x7e, 0x69, 0x93, 0x4b, 0x48, 0x1c, 0x3e, 0x5b, 0x6b, 0x73, 0x1a, + 0xa1, 0x24, 0x2e, 0xfd, 0x2d, 0x74, 0x9b, 0xe3, 0xe3, 0xc1, 0xb6, 0x3c, 0xe5, 0xd6, 0x07, 0xaa, + 0xda, 0x12, 0x6c, 0x18, 0x19, 0x02, 0x26, 0xa0, 0xfd, 0x70, 0x0d, 0xfc, 0xbd, 0x05, 0x20, 0xd2, + 0xc4, 0x04, 0x85, 0xc2, 0x2b, 0x98, 0xea, 0x52, 0x5f, 0x5e, 0x38, 0x44, 0xd7, 0x01, 0xfc, 0xc7, + 0xea, 0x02, 0x11, 0x3f, 0xe8, 0x98, 0x33, 0x97, 0x87, 0xc9, 0x83, 0x1b, 0xfb, 0xef, 0x94, 0x5c, + 0xba, 0xb6, 0x75, 0x9a, 0x89, 0x24, 0x78, 0xa0, 0xd7, 0xe6, 0x60, 0x01, 0x1e, 0xb5, 0x9c, 0x95, + ]) + TGL_TEST: bytes = bytes([ + 0xa3, 0x51, 0xb7, 0x28, 0xe6, 0x4b, 0xb5, 0x07, 0x87, 0xff, 0xc9, 0x7b, 0x15, 0x1b, 0x2c, 0x94, + 0xbc, 0x85, 0x3e, 0xe9, 0x4b, 0xb2, 0xa9, 0xc9, 0x5c, 0xa8, 0xc9, 0x33, 0xf7, 0x07, 0x71, 0x72, + 0x1f, 0xf6, 0x41, 0x13, 0x44, 0xe7, 0x5b, 0x8a, 0xb0, 0x58, 0xdc, 0x47, 0x64, 0x5b, 0x34, 0x88, + 0xf2, 0x11, 0xd0, 0x17, 0x58, 0x2d, 0xae, 0x79, 0x2c, 0x1d, 0xb7, 0xf2, 0x3e, 0xf9, 0x80, 0x80, + 0x93, 0xf5, 0xc2, 0xdc, 0xf5, 0x3c, 0x5a, 0x50, 0xa7, 0x04, 0x74, 0x59, 0xba, 0xce, 0x15, 0x85, + 0x05, 0xd0, 0x52, 0xf8, 0xee, 0x1b, 0x93, 0xc8, 0x41, 0x41, 0xf5, 0x83, 0xa8, 0xb2, 0xf5, 0x55, + 0x97, 0x66, 0xfc, 0x81, 0x7f, 0x43, 0x40, 0x6b, 0x46, 0xa5, 0xc5, 0x1a, 0xef, 0x81, 0x6d, 0xab, + 0x2a, 0x0e, 0x7b, 0x13, 0xfc, 0x8e, 0x57, 0x78, 0x5a, 0x63, 0xb7, 0xe5, 0x9b, 0x45, 0x51, 0x42, + 0x3c, 0x57, 0x2f, 0x80, 0x41, 0x77, 0x7c, 0xe6, 0x78, 0xcb, 0x24, 0x88, 0x4d, 0xe0, 0xc1, 0xeb, + 0x6d, 0xd9, 0x05, 0x8f, 0xfc, 0xe8, 0x74, 0x3e, 0x01, 0xb1, 0xe1, 0x89, 0x9b, 0x6c, 0xad, 0x47, + 0x38, 0xb1, 0xce, 0xbe, 0x49, 0x7b, 0x65, 0x7a, 0x7e, 0x9e, 0x3f, 0x24, 0xb3, 0x2e, 0xdb, 0x35, + 0x77, 0x5a, 0x31, 0x75, 0xcf, 0xe1, 0x71, 0x98, 0xbd, 0x61, 0x24, 0xd4, 0xd2, 0x97, 0xfd, 0xd0, + 0xbe, 0xeb, 0x0f, 0xbc, 0x60, 0xd7, 0x34, 0x1b, 0x8e, 0x55, 0x5f, 0xf7, 0xef, 0xf6, 0x03, 0xea, + 0x60, 0xba, 0x34, 0x9f, 0xef, 0x52, 0x38, 0xc3, 0xe6, 0xac, 0x08, 0x68, 0x64, 0xf1, 0x3c, 0x16, + 0x14, 0x03, 0xbf, 0xaa, 0x60, 0x01, 0x27, 0x0c, 0x4e, 0xb6, 0x03, 0xff, 0x45, 0xdd, 0x2b, 0xfd, + 0xf1, 0x86, 0xb7, 0x43, 0x83, 0x67, 0x1e, 0x1f, 0x33, 0x9e, 0xc7, 0x17, 0xb6, 0xef, 0x87, 0x91, + 0x02, 0x60, 0x59, 0x4f, 0x8b, 0x97, 0x19, 0x9c, 0x37, 0xfa, 0x4b, 0xef, 0x09, 0xc9, 0x3e, 0x06, + 0x68, 0x78, 0x2c, 0x13, 0x90, 0x7f, 0x1c, 0xc2, 0x5a, 0x31, 0xb6, 0x64, 0x7c, 0xcc, 0x42, 0xc7, + 0xce, 0x15, 0x50, 0x3a, 0xe7, 0x26, 0x6a, 0xe2, 0x08, 0x7f, 0x47, 0x40, 0x7f, 0x0b, 0x3a, 0x6d, + 0x94, 0x24, 0x59, 0xef, 0xdf, 0x68, 0x24, 0x01, 0x96, 0x00, 0xea, 0xe7, 0x2b, 0xc3, 0xa5, 0xb9, + 0x65, 0x60, 0x97, 0xd7, 0x61, 0x7f, 0xbf, 0xe8, 0x33, 0x1b, 0xf5, 0x51, 0xf4, 0x0c, 0x6b, 0x80, + 0x29, 0x7d, 0xf3, 0xbb, 0x26, 0xf0, 0x99, 0xd3, 0x3b, 0xca, 0x6d, 0x84, 0x8d, 0x04, 0xf8, 0x18, + 0x27, 0x02, 0x04, 0x9d, 0x17, 0xa6, 0xce, 0x8d, 0xd7, 0x96, 0x29, 0xac, 0x27, 0x5f, 0x40, 0x41, + 0x88, 0x09, 0xc0, 0x24, 0x7e, 0x84, 0xb7, 0x5d, 0xe3, 0x85, 0x50, 0x58, 0x98, 0x08, 0xc1, 0xf7, + ]) + TGL_PRODUCTION: 'Key' = bytes([ + 0x4d, 0xe2, 0x0c, 0xd3, 0x7d, 0x1c, 0x27, 0x9a, 0x30, 0x81, 0xed, 0x27, 0x55, 0x92, 0x95, 0xb6, + 0xd9, 0xa8, 0xd6, 0x96, 0x11, 0x0c, 0x5b, 0x48, 0xa2, 0x4a, 0x28, 0x8f, 0xa6, 0x0c, 0xb8, 0xbb, + 0x61, 0xf2, 0x1a, 0x1b, 0x7c, 0xf7, 0x76, 0xb1, 0xe5, 0x94, 0x8d, 0xa6, 0xf3, 0x6d, 0x9b, 0xc7, + 0x83, 0xf5, 0xaf, 0xca, 0x73, 0x49, 0x4a, 0xe5, 0x77, 0xf7, 0x1e, 0xd6, 0x4a, 0x76, 0x75, 0x15, + 0x18, 0x25, 0xd6, 0x87, 0x26, 0x39, 0xaf, 0xd0, 0xd5, 0x80, 0x05, 0x19, 0x72, 0x4f, 0xf4, 0xda, + 0x4c, 0xc4, 0x72, 0x7b, 0x43, 0x24, 0x54, 0x6d, 0x4a, 0xd4, 0xdb, 0x2f, 0xbb, 0xd2, 0xb8, 0xd4, + 0x6c, 0x1f, 0x5c, 0x9f, 0xcf, 0x90, 0xb9, 0x4f, 0xa5, 0x5f, 0x0b, 0x67, 0x25, 0xf7, 0x0a, 0x90, + 0x32, 0x4e, 0x2b, 0x1a, 0xe4, 0x3f, 0xaf, 0xab, 0x0a, 0x61, 0x45, 0x0b, 0xdd, 0xf9, 0x82, 0x4a, + 0x6b, 0xa1, 0x10, 0xff, 0x46, 0xec, 0xb8, 0x80, 0xef, 0x61, 0x35, 0xe8, 0x72, 0x5c, 0x24, 0x63, + 0x5f, 0x1e, 0x65, 0xfc, 0x29, 0x0f, 0xd7, 0xc7, 0xfb, 0xcf, 0x3d, 0xab, 0x7c, 0xf2, 0x03, 0xe9, + 0x96, 0x25, 0xc7, 0xd4, 0x66, 0x04, 0x95, 0x8d, 0xbe, 0xe5, 0xc2, 0xee, 0x04, 0x7b, 0x2d, 0x0e, + 0x8a, 0x93, 0x9e, 0x9b, 0xa2, 0xf0, 0x9c, 0x36, 0xcd, 0x27, 0x17, 0xfc, 0xfc, 0x10, 0x15, 0x47, + 0x6d, 0x4d, 0x61, 0xfb, 0x69, 0x8b, 0x6e, 0xa8, 0xa2, 0x7c, 0xc1, 0x87, 0x1c, 0x7d, 0x10, 0xb4, + 0xec, 0x4f, 0xce, 0xa6, 0xd1, 0xa2, 0xc4, 0x74, 0x65, 0x05, 0x94, 0x03, 0x63, 0xf8, 0x1c, 0xd1, + 0x6e, 0x69, 0x0f, 0xd4, 0x34, 0x10, 0x02, 0xf7, 0x71, 0x0d, 0x81, 0x12, 0xde, 0x7d, 0xb1, 0xdb, + 0xc0, 0x32, 0x4d, 0x3e, 0xe0, 0x45, 0xa3, 0x1d, 0x41, 0x6f, 0xe3, 0x35, 0x81, 0x8e, 0xb7, 0x7a, + 0x7a, 0x2a, 0xb5, 0x1a, 0xc6, 0xed, 0x73, 0x09, 0xa1, 0xbb, 0x5e, 0xe9, 0x77, 0x3a, 0x36, 0x98, + 0x8e, 0xde, 0xe2, 0x9b, 0x6e, 0x73, 0x68, 0x5e, 0xea, 0x52, 0x4b, 0x7e, 0xa2, 0x0e, 0x40, 0xc7, + 0x00, 0x3f, 0x09, 0xf9, 0x33, 0x32, 0x23, 0xbe, 0xb5, 0x00, 0x6b, 0x4f, 0x68, 0x5d, 0x76, 0x14, + 0x12, 0xd6, 0x90, 0xa6, 0xff, 0xb8, 0xfc, 0x50, 0xe5, 0x62, 0x94, 0xc3, 0x7c, 0xe8, 0x77, 0xf9, + 0x7c, 0xb5, 0x5f, 0xed, 0x98, 0x80, 0xcc, 0xc1, 0x1a, 0xa1, 0x61, 0x2d, 0xea, 0x39, 0x49, 0xa3, + 0xb7, 0xdb, 0xb3, 0x15, 0x47, 0xfc, 0x2f, 0x12, 0x1c, 0x33, 0xe8, 0x31, 0x71, 0xb7, 0x5a, 0xc7, + 0x63, 0x83, 0xa8, 0xa9, 0x6d, 0xfa, 0x40, 0x9c, 0xe5, 0x9c, 0x5e, 0x76, 0x2b, 0x9c, 0xd3, 0x6b, + 0x73, 0xd4, 0xf3, 0xa3, 0x49, 0xf6, 0x86, 0x85, 0x96, 0x73, 0xa8, 0x31, 0xc8, 0x66, 0xfe, 0x9c, + ]) + ADL_PRODUCTION: 'Key' = bytes([ + 0xc3, 0xa9, 0x32, 0xd6, 0xcf, 0xe6, 0xab, 0xb0, 0xea, 0xa5, 0x48, 0x13, 0x48, 0xc7, 0x58, 0xf5, + 0xe4, 0x66, 0xeb, 0x82, 0x2c, 0xf5, 0x7a, 0xbd, 0x73, 0x94, 0x45, 0x98, 0xb0, 0x92, 0x79, 0x4f, + 0x57, 0x86, 0xf5, 0x9c, 0x1b, 0x6c, 0x45, 0x16, 0x22, 0x97, 0xa0, 0xb4, 0x6e, 0x1e, 0x42, 0x30, + 0xb3, 0x3d, 0xf1, 0x9c, 0x3e, 0xd4, 0xcf, 0x7e, 0xf2, 0x6b, 0x82, 0xc2, 0x75, 0x9d, 0xaf, 0x1c, + 0x74, 0xf1, 0xc1, 0x15, 0x9a, 0xa5, 0x09, 0xe2, 0xee, 0x48, 0x9a, 0x25, 0xba, 0x9a, 0x96, 0xbe, + 0x28, 0xd7, 0xaf, 0xec, 0xc5, 0xcc, 0xc2, 0x70, 0xba, 0x6d, 0xeb, 0xdd, 0x7d, 0x6a, 0x47, 0xdc, + 0x70, 0xed, 0xe9, 0x20, 0x00, 0x5f, 0xcb, 0x28, 0x80, 0x63, 0x87, 0x06, 0x18, 0xbb, 0x09, 0xec, + 0xbf, 0x83, 0x1c, 0x7f, 0xd4, 0x8c, 0x3c, 0xac, 0xd9, 0x90, 0xde, 0x50, 0xed, 0x20, 0xab, 0xc3, + 0xb7, 0xcc, 0xe3, 0x27, 0x92, 0xe9, 0x25, 0x74, 0xea, 0x42, 0x1b, 0x43, 0xb9, 0xeb, 0xf4, 0xd5, + 0x2c, 0xdc, 0xa8, 0xf5, 0x4c, 0x05, 0xab, 0x34, 0x64, 0x73, 0xea, 0xe7, 0x7f, 0x1d, 0x9a, 0xe2, + 0x86, 0x72, 0x98, 0x9a, 0x2f, 0x4c, 0x49, 0xa5, 0xbe, 0x8d, 0xa7, 0x96, 0x63, 0x08, 0x35, 0x89, + 0x8e, 0xd3, 0xe9, 0x4e, 0xf1, 0x06, 0xa5, 0x3a, 0x5b, 0x28, 0x82, 0xd2, 0x9d, 0x9d, 0xd0, 0x3c, + 0x7d, 0xce, 0xe1, 0xeb, 0x04, 0xb7, 0xf1, 0xd4, 0x2f, 0x68, 0xc2, 0xfb, 0x31, 0x08, 0x08, 0x7f, + 0xb1, 0x30, 0x95, 0xd1, 0xce, 0xe6, 0xf3, 0xae, 0x84, 0x30, 0xf0, 0x13, 0xd0, 0xf8, 0xe5, 0xee, + 0x02, 0xb7, 0xfd, 0x4f, 0xa8, 0xb3, 0x06, 0x1e, 0xf0, 0x8c, 0xce, 0xe1, 0x9d, 0xb1, 0xdc, 0x8e, + 0x3d, 0xc6, 0xd6, 0x7c, 0xe1, 0xfc, 0xd4, 0xa3, 0x1c, 0x70, 0x9a, 0xf5, 0x31, 0xd6, 0x8e, 0xe7, + 0x50, 0xae, 0xcc, 0xd7, 0x5c, 0xa7, 0xc2, 0xe6, 0xed, 0x7f, 0x0e, 0x1e, 0x91, 0x5c, 0x48, 0x70, + 0x3e, 0x7a, 0xa7, 0xc9, 0x83, 0x97, 0x97, 0xc3, 0x04, 0xf4, 0x59, 0x74, 0x5b, 0xf2, 0x3c, 0x79, + 0x8c, 0xf3, 0x63, 0xc8, 0xf4, 0x71, 0x6e, 0x08, 0xc0, 0x79, 0xaf, 0x8c, 0xe5, 0xf4, 0x0a, 0x53, + 0x42, 0x68, 0x4b, 0xce, 0xad, 0x4e, 0xb4, 0x0c, 0xc5, 0x47, 0xdf, 0x86, 0x69, 0xa0, 0xad, 0xdc, + 0x65, 0x6e, 0x3e, 0xf4, 0x9a, 0xc9, 0xbf, 0x24, 0x22, 0x0f, 0xb9, 0x08, 0x58, 0xe8, 0x96, 0x47, + 0x70, 0x48, 0x3f, 0x4f, 0xb0, 0x96, 0xac, 0x9e, 0xf8, 0x3f, 0x6c, 0x2a, 0xc3, 0xea, 0x4e, 0xb8, + 0x60, 0x55, 0xc4, 0x77, 0x7b, 0x81, 0x77, 0x3e, 0xe6, 0x69, 0x98, 0xe8, 0x3c, 0x6a, 0xd7, 0xca, + 0x5b, 0x6f, 0xdc, 0xde, 0x73, 0x19, 0xf3, 0xa2, 0xd0, 0x2e, 0x01, 0xf0, 0xfd, 0xfd, 0xa9, 0xbb, + ]) + + +def get_key_enum(key: bytes) -> Key: + k: Key + for k in Key: + if k.value == key: + return k + return Key.UNKNOWN diff --git a/tools/intel-ipu-fw-info/intel_ipu_fw_info/parser.py b/tools/intel-ipu-fw-info/intel_ipu_fw_info/parser.py new file mode 100644 index 0000000..45e241a --- /dev/null +++ b/tools/intel-ipu-fw-info/intel_ipu_fw_info/parser.py @@ -0,0 +1,199 @@ +import datetime +import json +import string +import struct +from typing import Any + +from .key import Key, get_key_enum +from .spec import ( + FirmwareInfo, + ComponentStructFormat, + CSE, + CSESubcomponentHeader, + CSS, + CSS4, + Component, + ComponentExtension, + OtherComponentExtension, + PlatformFirmwareAuthenticationComponentExtension, + bcddate) + + +class ByteEncoder(json.JSONEncoder): + def default(self, obj: Any) -> Any: + if isinstance(obj, bytes | bytearray): + b: bytes + if all(b in string.printable.encode() for b in obj): + return obj.decode() + return ' '.join(map(lambda b: '{:02X}'.format(b), obj)) + if isinstance(obj, bcddate): + return repr(obj) + if isinstance(obj, Key | datetime.date | datetime.datetime): + return str(obj) + return super().default(obj) + + +def get_css_4(block: bytes, block_size: int) -> CSS4: + type_: int + header_length: int + header_version: int + reserved_0: int + mod_vendor: int + date: int + size: int + header_id: bytes + padding: int + firmware_version: tuple[int, int, int, int] + firmware_version_0: int + firmware_version_1: int + firmware_version_2: int + firmware_version_3: int + svn: int + meu_version: tuple[int, int, int, int] + meu_version_0: int + meu_version_1: int + meu_version_2: int + meu_version_3: int + reserved_1: bytes + modulus_size: int + exponent_size: int + (type_, header_length, header_version, reserved_0, mod_vendor, date, size, header_id, padding, + firmware_version_0, firmware_version_1, firmware_version_2, firmware_version_3, svn, meu_version_0, + meu_version_1, meu_version_2, meu_version_3, reserved_1, modulus_size, exponent_size) = struct.unpack( + ComponentStructFormat.CSS_4_FIXED, block[:struct.calcsize(ComponentStructFormat.CSS_4_FIXED)]) + bcd_date: bcddate = bcddate(date) + + firmware_version = (firmware_version_0, firmware_version_1, firmware_version_2, firmware_version_3) + meu_version = (meu_version_0, meu_version_1, meu_version_2, meu_version_3) + + signature_format: str = ComponentStructFormat.CSS_4_DATA.format( + modulus_size=modulus_size * 4, exponent_size=exponent_size * 4, signature_size=modulus_size * 4) + modulus: bytes + exponent: bytes + signature: bytes + (modulus, exponent, signature) = struct.unpack( + signature_format, block[struct.calcsize(ComponentStructFormat.CSS_4_FIXED):struct.calcsize( + ComponentStructFormat.CSS_4_FIXED + signature_format)]) + + extensions: list[ComponentExtension] = list() + extension_index: int = 0 + current_offset: int = struct.calcsize(ComponentStructFormat.CSS_4_FIXED + signature_format) + extension_type: int + extension_size: int + while current_offset < block_size: + (extension_type, extension_size) = struct.unpack( + ComponentStructFormat.COMPONENT_EXTENSION_BEGINNING_PIECE, + block[current_offset:current_offset + struct.calcsize( + ComponentStructFormat.COMPONENT_EXTENSION_BEGINNING_PIECE)]) + if extension_type == 0xFFFFFFFF: + current_offset += 4 + continue + extension: ComponentExtension = get_component_extension(block[current_offset:], extension_index) + extensions.append(extension) + extension_index += 1 + current_offset += extension_size + + return CSS4( + type=type_, header_length=header_length, header_version=header_version, reserved_0=reserved_0, + mod_vendor=mod_vendor, date=bcd_date, size=size, header_id=header_id, padding=padding, + firmware_version=firmware_version, svn=svn, meu_version=meu_version, reserved_1=reserved_1, + modulus_size=modulus_size, exponent_size=exponent_size, modulus=modulus, exponent=exponent, signature=signature, + extensions=extensions) + + +def get_css(block: bytes, block_size: int) -> CSS: + version: int + (version,) = struct.unpack( + ComponentStructFormat.CSS_BEGINNING_PIECE, + block[:struct.calcsize(ComponentStructFormat.CSS_BEGINNING_PIECE)]) + + if version == 4: + return get_css_4(block, block_size) + + raise ValueError('unsupported CSS') + + +def get_cse_subcomponent_headers(block: bytes, num: int = 0) -> list[CSESubcomponentHeader]: + res: list[CSESubcomponentHeader] = list() + + for _ in range(num): + name: bytes + data_offset: int + data_size: int + reserved: int + (name, data_offset, data_size, reserved) = struct.unpack( + ComponentStructFormat.CSE_SUBCOMPONENT_HEADER, + block[:struct.calcsize(ComponentStructFormat.CSE_SUBCOMPONENT_HEADER)]) + name = name.rstrip(b'\0') + block = block[struct.calcsize(ComponentStructFormat.CSE_SUBCOMPONENT_HEADER):] + res.append(CSESubcomponentHeader(name=name, offset=data_offset, size=data_size, reserved=reserved)) + return res + + +def get_component_extension(block: bytes, extension_id: int) -> ComponentExtension: + type_: int + size: int + (type_, size) = struct.unpack( + ComponentStructFormat.COMPONENT_EXTENSION_BEGINNING_PIECE, + block[:struct.calcsize(ComponentStructFormat.COMPONENT_EXTENSION_BEGINNING_PIECE)]) + + if type_ == 15: + name: bytes + vcn: int + bitmap: bytes + svn: int + (name, vcn, bitmap, svn) = struct.unpack( + ComponentStructFormat.PLATFORM_FIRMWARE_AUTHENTICATION_COMPONENT_EXTENSION, + block[:struct.calcsize(ComponentStructFormat.PLATFORM_FIRMWARE_AUTHENTICATION_COMPONENT_EXTENSION)]) + return PlatformFirmwareAuthenticationComponentExtension( + type=type_, size=size, name=name, vcn=vcn, bitmap=bitmap, svn=svn, extension_id=extension_id) + return OtherComponentExtension(type=type_, size=size, extension_id=extension_id) + + +def get_cse_subcomponents(block: bytes, headers: list[CSESubcomponentHeader]) -> list[Component]: + res: list[Component] = list() + + header: CSESubcomponentHeader + for header in headers: + if header.name.endswith(b'.man'): + res.append(get_css(block[header.offset:], header.size)) + continue + res.append(get_component_extension(block[header.offset:], header.size)) + return res + + +def get_cse(block: bytes) -> CSE: + if not block.startswith(CSE.signature): + raise ValueError('not recognized firmware') + + signature: bytes + num_subcomponent: int + header_version: int + header_length: int + checksum: int + partition_name: bytes + (signature, num_subcomponent, header_version, header_length, checksum, partition_name) = struct.unpack( + ComponentStructFormat.CSE, block[:struct.calcsize(ComponentStructFormat.CSE)]) + + cse_subcomponent_headers: list[CSESubcomponentHeader] = get_cse_subcomponent_headers( + block[header_length:], num=num_subcomponent) + cse_subcomponents: list[Component] = get_cse_subcomponents(block, headers=cse_subcomponent_headers) + + return CSE( + signature=signature, + num_subcomponent=num_subcomponent, + header_version=header_version, + header_length=header_length, + checksum=checksum, + partition_name=partition_name, + subcomponent_headers=cse_subcomponent_headers, + subcomponents=cse_subcomponents) + + +def get_firmware_info(block: bytes) -> FirmwareInfo: + cse: CSE = get_cse(block) + + return FirmwareInfo( + timestamp=datetime.date.fromisoformat(repr(cse.subcomponents[0].date)), + version='.'.join(map(str, cse.subcomponents[0].firmware_version)), + key=get_key_enum(cse.subcomponents[0].modulus)) diff --git a/tools/intel-ipu-fw-info/intel_ipu_fw_info/spec.py b/tools/intel-ipu-fw-info/intel_ipu_fw_info/spec.py new file mode 100644 index 0000000..a75373b --- /dev/null +++ b/tools/intel-ipu-fw-info/intel_ipu_fw_info/spec.py @@ -0,0 +1,105 @@ +import dataclasses +import datetime +import decimal +import enum + +from .key import Key + + +# JSONEncoder does not let us customize the serialization of int, thus we inherit Decimal instead +class bcddate(decimal.Decimal): + def __repr__(self, *args, **kwargs) -> str: + bcd_date_bytes: bytes = int(self).to_bytes(4, 'big') + return '{}-{:02d}-{:02d}'.format( + 2000 + int(hex(bcd_date_bytes[1])[2:]), + int(hex(bcd_date_bytes[2])[2:]), + int(hex(bcd_date_bytes[3])[2:])) + + +class ComponentStructFormat(enum.StrEnum): + CSE: 'ComponentStructFormat' = '4sIHBB4s' + CSE_SUBCOMPONENT_HEADER: 'ComponentStructFormat' = '12sIII' + CSS_BEGINNING_PIECE: 'ComponentStructFormat' = 'I' + CSS_4_FIXED: 'ComponentStructFormat' = 'IIIIIII4sIHHHHIHHHH64sII' + CSS_4_DATA: 'ComponentStructFormat' = '{modulus_size}s{exponent_size}s{signature_size}s' + COMPONENT_EXTENSION_BEGINNING_PIECE: 'ComponentStructFormat' = 'II' + PLATFORM_FIRMWARE_AUTHENTICATION_COMPONENT_EXTENSION: 'ComponentStructFormat' = '4sI16sI' + + +@dataclasses.dataclass +class Component: + pass + + +@dataclasses.dataclass +class ComponentExtension(Component): + type: int + size: int + extension_id: int + + +@dataclasses.dataclass +class OtherComponentExtension(ComponentExtension): + pass + + +@dataclasses.dataclass +class PlatformFirmwareAuthenticationComponentExtension(ComponentExtension): + name: bytes + vcn: int + bitmap: bytes + svn: int + + +@dataclasses.dataclass +class CSESubcomponentHeader(Component): + name: bytes + offset: int + size: int + reserved: int + + +@dataclasses.dataclass(kw_only=True) +class CSE(Component): + signature: bytes = b'$CPD' + num_subcomponent: int + header_version: int + header_length: int + checksum: int + partition_name: bytes + subcomponent_headers: list[CSESubcomponentHeader] + subcomponents: list[Component] + + +@dataclasses.dataclass +class CSS(Component): + type: int + + +@dataclasses.dataclass +class CSS4(CSS): + header_length: int + header_version: int + reserved_0: int + mod_vendor: int + date: bcddate + size: int + header_id: bytes + padding: int + firmware_version: tuple[int, int, int, int] + svn: int + meu_version: tuple[int, int, int, int] + reserved_1: bytes + modulus_size: int + exponent_size: int + modulus: bytes # 4 times modulus_size + exponent: bytes # 4 times exponent_size + signature: bytes # 4 times modulus_size + extensions: list[ComponentExtension] + + +@dataclasses.dataclass +class FirmwareInfo: + timestamp: datetime.date + version: str + key: Key diff --git a/tools/intel-ipu-fw-info/pyproject.toml b/tools/intel-ipu-fw-info/pyproject.toml new file mode 100644 index 0000000..15aedd8 --- /dev/null +++ b/tools/intel-ipu-fw-info/pyproject.toml @@ -0,0 +1,53 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "intel-ipu-fw-info" +description = '' +readme = "README.md" +requires-python = ">=3.11" +keywords = [] +authors = [ + { name = "Johann Chang", email = "mr.changyuheng@gmail.com" }, +] +classifiers = [ + "Development Status :: 4 - Beta", + "Programming Language :: Python", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: Implementation :: CPython", +] +dependencies = [] +dynamic = ["version"] + +[project.scripts] +intel-ipu-fw-info = "intel_ipu_fw_info.cli:main" + +[tool.hatch.version] +path = "intel_ipu_fw_info/__about__.py" + +[tool.hatch.envs.default] +dependencies = [ + "pytest", + "pytest-cov", +] +[tool.hatch.envs.default.scripts] +cov = "pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=intel_ipu_fw_info --cov=tests {args}" +no-cov = "cov --no-cov {args}" + +[[tool.hatch.envs.test.matrix]] +python = ["311"] + +[tool.coverage.run] +branch = true +parallel = true +omit = [ + "intel_ipu_fw_info/__about__.py", +] + +[tool.coverage.report] +exclude_lines = [ + "no cov", + "if __name__ == .__main__.:", + "if TYPE_CHECKING:", +] diff --git a/tools/intel-ipu-fw-info/tests/__init__.py b/tools/intel-ipu-fw-info/tests/__init__.py new file mode 100644 index 0000000..e69de29