diff options
| author | PMR <pmr@pmr-lander> | 2020-08-18 09:35:54 +0000 |
|---|---|---|
| committer | PMR <pmr@pmr-lander> | 2020-08-18 09:35:54 +0000 |
| commit | 388f786c25e53eee19d1cd72a87db358cae29845 (patch) | |
| tree | adbe6a835b9eb5fe53ebba06c1f432dd9e79022b | |
| parent | 0c6f30f792fd0f9970d2cd8c47c24d810abf46e7 (diff) | |
| parent | 877d7d8851d75b16823c75b8db67dc01f443334e (diff) | |
Merge #387514 from ~kchsieh/plainbox-provider-checkbox/+git/plainbox-provider-checkbox:add-sof-firmware-sig-check
| -rwxr-xr-x | bin/sof_ri_info.py | 1385 | ||||
| -rw-r--r-- | units/audio/jobs.pxu | 16 | ||||
| -rw-r--r-- | units/audio/test-plan.pxu | 1 |
3 files changed, 1402 insertions, 0 deletions
diff --git a/bin/sof_ri_info.py b/bin/sof_ri_info.py new file mode 100755 index 0000000..638fa75 --- /dev/null +++ b/bin/sof_ri_info.py @@ -0,0 +1,1385 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright (c) 2019, Intel Corporation. All rights reserved. +# +# Author: Marcin Maka <marcin.maka@linux.intel.com> + +""" Parses manifests included in sof binary and prints extracted metadata + in readable form. +""" + +# pylint: disable=too-few-public-methods +# pylint: disable=too-many-arguments +# pylint: disable=too-many-instance-attributes + +import sys +import argparse +import struct + +# To extend the DSP memory layout list scroll down to DSP_MEM_SPACE_EXT + +# Public keys signatures recognized by parse_css_manifest() +# - add a new one as array of bytes and append entry to KNOWN_KEYS below. + +APL_INTEL_PROD_KEY = bytes([0x1f, 0xf4, 0x58, 0x74, 0x64, 0xd4, 0xae, 0x90, + 0x03, 0xb6, 0x71, 0x0d, 0xb5, 0xaf, 0x6d, 0xd6, + 0x96, 0xce, 0x28, 0x95, 0xd1, 0x5b, 0x40, 0x59, + 0xcd, 0xdf, 0x0c, 0x55, 0xd2, 0xc1, 0xbd, 0x58, + 0xc3, 0x0d, 0x83, 0xe2, 0xac, 0xfa, 0xe0, 0xcc, + 0x54, 0xf6, 0x5f, 0x72, 0xc2, 0x11, 0x05, 0x93, + 0x1d, 0xb7, 0xe4, 0x4f, 0xa4, 0x95, 0xf5, 0x84, + 0x77, 0x07, 0x24, 0x6e, 0x72, 0xce, 0x57, 0x41, + 0xf2, 0x0b, 0x49, 0x49, 0x0c, 0xe2, 0x76, 0xf8, + 0x19, 0xc7, 0x9f, 0xe1, 0xca, 0x77, 0x20, 0x1b, + 0x5d, 0x1d, 0xed, 0xee, 0x5c, 0x54, 0x1d, 0xf6, + 0x76, 0x14, 0xce, 0x6a, 0x24, 0x80, 0xc9, 0xce, + 0x2e, 0x92, 0xe9, 0x35, 0xc7, 0x1a, 0xe9, 0x97, + 0x7f, 0x25, 0x2b, 0xa8, 0xf3, 0xc1, 0x4d, 0x6b, + 0xae, 0xd9, 0xcd, 0x0c, 0xbb, 0x08, 0x6d, 0x2b, + 0x01, 0x44, 0xe2, 0xb9, 0x44, 0x4e, 0x4d, 0x5c, + 0xdf, 0x8a, 0x89, 0xa5, 0x3c, 0x27, 0xa0, 0x54, + 0xde, 0xc5, 0x5b, 0xde, 0x58, 0x10, 0x8c, 0xaa, + 0xc4, 0x37, 0x5b, 0x73, 0x58, 0xfb, 0xe3, 0xcf, + 0x57, 0xf5, 0x65, 0xd3, 0x19, 0x06, 0xed, 0x36, + 0x47, 0xb0, 0x91, 0x67, 0xec, 0xc1, 0xe1, 0x7b, + 0x4f, 0x85, 0x66, 0x61, 0x31, 0x99, 0xfc, 0x98, + 0x7a, 0x56, 0x70, 0x95, 0x85, 0x52, 0xa0, 0x30, + 0x37, 0x92, 0x11, 0x9e, 0x7f, 0x33, 0x44, 0xd3, + 0x81, 0xfd, 0x14, 0x74, 0x51, 0x1c, 0x01, 0x14, + 0xc8, 0x4b, 0xf6, 0xd6, 0xeb, 0x67, 0xef, 0xfc, + 0x0a, 0x5f, 0xcc, 0x31, 0x73, 0xf8, 0xa9, 0xe3, + 0xcb, 0xb4, 0x8b, 0x91, 0xa1, 0xf0, 0xb9, 0x6e, + 0x1f, 0xea, 0xd3, 0xa3, 0xe4, 0x0f, 0x96, 0x74, + 0x3c, 0x17, 0x5b, 0x68, 0x7c, 0x87, 0xfc, 0x90, + 0x10, 0x89, 0x23, 0xca, 0x5d, 0x17, 0x5b, 0xc1, + 0xb5, 0xc2, 0x49, 0x4e, 0x2a, 0x5f, 0x47, 0xc2]) + +CNL_INTEL_PROD_KEY = bytes([0x41, 0xa0, 0x3e, 0x14, 0x1e, 0x7e, 0x29, 0x72, + 0x89, 0x97, 0xc2, 0xa7, 0x7d, 0xbc, 0x1d, 0x25, + 0xf4, 0x9a, 0xa8, 0xb7, 0x89, 0x10, 0x73, 0x31, + 0x58, 0xbd, 0x46, 0x55, 0x78, 0xcf, 0xd9, 0xe1, + 0x7d, 0xfa, 0x24, 0x23, 0xfa, 0x5c, 0x7c, 0xc9, + 0x3d, 0xc8, 0xb5, 0x74, 0x87, 0xa, 0x8c, 0xe7, + 0x33, 0xc2, 0x71, 0x26, 0xb1, 0x4d, 0x32, 0x45, + 0x23, 0x17, 0xcb, 0xa6, 0xa2, 0xd0, 0xcc, 0x9e, + 0x2b, 0xa6, 0x9, 0x42, 0x52, 0xf1, 0xe6, 0xbd, + 0x73, 0x92, 0x2a, 0xfb, 0x7f, 0xc4, 0x8d, 0x5, + 0xec, 0x69, 0x7f, 0xd4, 0xa2, 0x6c, 0x46, 0xd4, + 0x5d, 0x92, 0x1d, 0x17, 0x75, 0x39, 0x16, 0x4c, + 0x61, 0xa8, 0xda, 0x93, 0xd6, 0x26, 0x23, 0xa, + 0xc8, 0x2d, 0xcc, 0x81, 0xf4, 0xcc, 0x85, 0x42, + 0xaa, 0xa3, 0x15, 0x8, 0x62, 0x8f, 0x72, 0x9b, + 0x5f, 0x90, 0x2f, 0xd5, 0x94, 0xdc, 0xad, 0xf, + 0xa9, 0x8, 0x8c, 0x2e, 0x20, 0xf4, 0xdf, 0x12, + 0xf, 0xe2, 0x1e, 0xeb, 0xfb, 0xf7, 0xe9, 0x22, + 0xef, 0xa7, 0x12, 0x3d, 0x43, 0x3b, 0x62, 0x8e, + 0x2e, 0xeb, 0x78, 0x8, 0x6e, 0xd0, 0xb0, 0xea, + 0x37, 0x43, 0x16, 0xd8, 0x11, 0x5a, 0xb5, 0x5, + 0x60, 0xf2, 0x91, 0xa7, 0xaa, 0x7d, 0x7, 0x17, + 0xb7, 0x5b, 0xec, 0x45, 0xf4, 0x4a, 0xaf, 0x5c, + 0xa3, 0x30, 0x62, 0x8e, 0x4d, 0x63, 0x2, 0x2, + 0xed, 0x4b, 0x1f, 0x1b, 0x9a, 0x2, 0x29, 0x9, + 0xc1, 0x7a, 0xc5, 0xeb, 0xc7, 0xdb, 0xa1, 0x6f, + 0x61, 0x31, 0xfa, 0x7b, 0x3b, 0xe0, 0x6a, 0x1c, + 0xee, 0x55, 0xed, 0xf0, 0xf9, 0x7a, 0xaf, 0xaa, + 0xc7, 0x76, 0xf5, 0xfb, 0x6a, 0xbc, 0x65, 0xde, + 0x42, 0x3e, 0x1c, 0xdf, 0xcc, 0x69, 0x75, 0x1, + 0x38, 0x8, 0x66, 0x20, 0xea, 0x6, 0x91, 0xb8, + 0xcd, 0x1d, 0xfa, 0xfd, 0xe8, 0xa0, 0xba, 0x91]) + +ICL_INTEL_PROD_KEY = bytes([0x63, 0xdf, 0x54, 0xe3, 0xc1, 0xe5, 0xd9, 0xd2, + 0xb8, 0xb5, 0x13, 0xb3, 0xec, 0xc2, 0x64, 0xb5, + 0x16, 0xb4, 0xfc, 0x56, 0x92, 0x67, 0x17, 0xc7, + 0x91, 0x7b, 0x3d, 0xb0, 0x22, 0xbf, 0x7f, 0x92, + 0x39, 0x35, 0xcc, 0x64, 0x1c, 0xad, 0x8, 0x75, + 0xe7, 0x67, 0xb, 0x8, 0xf8, 0x57, 0xdb, 0x9c, + 0xde, 0xab, 0xe, 0xbd, 0x27, 0x5f, 0x5, 0x51, + 0xcf, 0x6e, 0x3e, 0xc9, 0xdd, 0xe6, 0x51, 0x14, + 0x57, 0xe1, 0x8a, 0x23, 0xae, 0x7a, 0xa5, 0x5f, + 0xdc, 0x16, 0x13, 0x1b, 0x28, 0x3b, 0xab, 0xf1, + 0xc3, 0xb5, 0x73, 0xc0, 0x72, 0xd8, 0x86, 0x7a, + 0x76, 0x3a, 0x2, 0xbe, 0x2f, 0x3e, 0xfe, 0x93, + 0x83, 0xa1, 0xd, 0xa0, 0xfc, 0x26, 0x7f, 0x6b, + 0x2e, 0x5a, 0xfd, 0xac, 0x6b, 0x53, 0xd3, 0xb8, + 0xff, 0x5e, 0xc7, 0x5, 0x25, 0xff, 0xe7, 0x78, + 0x9c, 0x45, 0xe4, 0x17, 0xbd, 0xf4, 0x52, 0x4e, + 0x3c, 0xa2, 0xa, 0x4d, 0x54, 0xb5, 0x40, 0x30, + 0xb3, 0x48, 0xba, 0x6c, 0xfa, 0x63, 0xc0, 0x65, + 0x2e, 0xde, 0x9, 0x2e, 0xa1, 0x95, 0x85, 0xc0, + 0x78, 0xd9, 0x98, 0x64, 0x3c, 0x29, 0x2e, 0x48, + 0x66, 0x1e, 0xaf, 0x1d, 0xa0, 0x7c, 0x15, 0x3, + 0x7f, 0x9e, 0x5f, 0x38, 0xf5, 0xc1, 0xe1, 0xe9, + 0xbe, 0x77, 0xa2, 0x9c, 0x83, 0xf2, 0x25, 0x54, + 0x22, 0xfe, 0x29, 0x66, 0x5, 0xc2, 0xc9, 0x6b, + 0x8b, 0xa6, 0xa3, 0xf9, 0xb1, 0x6b, 0xaf, 0xe7, + 0x14, 0x77, 0xff, 0x17, 0xc9, 0x7c, 0x7c, 0x4e, + 0x83, 0x28, 0x2a, 0xe5, 0xc3, 0xcc, 0x6e, 0x25, + 0xa, 0x62, 0xbb, 0x97, 0x44, 0x86, 0x7c, 0xa2, + 0xd4, 0xf1, 0xd4, 0xf8, 0x8, 0x17, 0xf4, 0x6c, + 0xcc, 0x95, 0x99, 0xd4, 0x86, 0x37, 0x4, 0x9f, + 0x5, 0x76, 0x1b, 0x44, 0x55, 0x75, 0xd9, 0x32, + 0x35, 0xf1, 0xec, 0x4d, 0x93, 0x73, 0xe6, 0xc4]) + +TGL_INTEL_PROD_KEY = bytes([0xd3, 0x72, 0x92, 0x99, 0x4e, 0xb9, 0xcd, 0x67, + 0x41, 0x86, 0x16, 0x77, 0x35, 0xa1, 0x34, 0x85, + 0x43, 0x96, 0xd9, 0x53, 0x76, 0x4d, 0xd0, 0x63, + 0x17, 0x72, 0x96, 0xee, 0xf6, 0xdc, 0x50, 0x53, + 0x4b, 0x4, 0xaa, 0xfe, 0x3d, 0xd7, 0x21, 0x29, + 0x79, 0x6, 0x76, 0xee, 0xb3, 0x70, 0x23, 0x8, + 0x26, 0xa8, 0x83, 0x3d, 0x70, 0x13, 0x9d, 0x65, + 0xcb, 0xd5, 0xc6, 0xf, 0x92, 0x93, 0x38, 0x29, + 0x19, 0xa6, 0x7c, 0xbf, 0xf1, 0x76, 0x75, 0x2, + 0x9e, 0x32, 0x8f, 0x1f, 0x5, 0xa6, 0x2d, 0x89, + 0x6d, 0x38, 0xba, 0x38, 0xd, 0xf1, 0xe9, 0xe8, + 0xed, 0xf7, 0x6c, 0x20, 0x8d, 0x91, 0xc, 0xf8, + 0xdd, 0x9a, 0x56, 0xd3, 0xf7, 0xbf, 0x3c, 0xda, + 0xc8, 0x5d, 0xb, 0xef, 0x20, 0x5a, 0xc1, 0x5f, + 0x91, 0x94, 0xee, 0x90, 0xb8, 0xfc, 0x2c, 0x31, + 0x75, 0xc3, 0x7e, 0x86, 0xf6, 0x4f, 0x45, 0x4c, + 0x64, 0xe1, 0xe9, 0xe5, 0xcd, 0xf0, 0xec, 0xef, + 0xa7, 0xbd, 0x31, 0x62, 0x40, 0xa8, 0x48, 0x52, + 0xd5, 0x23, 0xce, 0x4, 0x45, 0x2f, 0xb, 0x3d, + 0xe0, 0x7a, 0xcf, 0xe5, 0x2a, 0x45, 0x5e, 0x91, + 0x1d, 0x41, 0xa7, 0x40, 0x85, 0x34, 0xe, 0x50, + 0x45, 0x59, 0xbf, 0xd, 0xa6, 0x6, 0xf9, 0xf6, + 0xce, 0xa2, 0x76, 0x72, 0x0, 0x62, 0x73, 0x37, + 0x1a, 0xbe, 0xd2, 0xe3, 0x1b, 0x7b, 0x26, 0x7b, + 0x32, 0xaa, 0x79, 0xed, 0x59, 0x23, 0xb6, 0xdb, + 0x9f, 0x3c, 0x3d, 0x65, 0xf3, 0xbb, 0x4b, 0xb4, + 0x97, 0xaa, 0x2a, 0xae, 0x48, 0xf4, 0xc5, 0x59, + 0x8d, 0x82, 0x4a, 0xb, 0x15, 0x4d, 0xd5, 0x4, + 0xa6, 0xc1, 0x2d, 0x83, 0x19, 0xc4, 0xc6, 0x49, + 0xba, 0x0, 0x1b, 0x2b, 0x70, 0xb, 0x26, 0x7c, + 0xb8, 0x94, 0x18, 0xe4, 0x9a, 0xf6, 0x5a, 0x68, + 0x9d, 0x44, 0xd2, 0xed, 0xd5, 0x67, 0x42, 0x47, + 0x5f, 0x73, 0xc5, 0xa7, 0xe5, 0x87, 0xa9, 0x4d, + 0xae, 0xc1, 0xb, 0x2c, 0x46, 0x16, 0xd7, 0x4e, + 0xf0, 0xdc, 0x61, 0x58, 0x51, 0xb1, 0x2, 0xbc, + 0xca, 0x17, 0xb1, 0x1a, 0xa, 0x96, 0x3b, 0x25, + 0x1c, 0x63, 0x56, 0x65, 0x20, 0x6e, 0x1b, 0x21, + 0xb1, 0x94, 0x7a, 0xf5, 0xbf, 0x83, 0x21, 0x86, + 0x38, 0xf1, 0x66, 0x1a, 0xa, 0x75, 0x73, 0xa, + 0xe, 0xc7, 0x64, 0x68, 0xc7, 0xf9, 0xc3, 0x4a, + 0x73, 0xfb, 0x86, 0xa5, 0x7, 0xb8, 0x8b, 0xf0, + 0xa3, 0x3b, 0xa9, 0x8f, 0x33, 0xa7, 0xce, 0xfe, + 0x36, 0x60, 0xbd, 0x5, 0xf0, 0x9a, 0x30, 0xe5, + 0xe1, 0x43, 0x25, 0x1c, 0x1, 0x4a, 0xd4, 0x23, + 0x1e, 0x8f, 0xb9, 0xdd, 0xd8, 0xb2, 0x24, 0xef, + 0x36, 0x4d, 0x5b, 0x8f, 0xba, 0x4f, 0xe9, 0x48, + 0xe7, 0x51, 0x42, 0x59, 0x56, 0xa, 0x1c, 0xf, + 0x5d, 0x62, 0x4a, 0x80, 0x96, 0x31, 0xf8, 0xb5]) + +COMMUNITY_KEY = bytes([0x85, 0x00, 0xe1, 0x68, 0xaa, 0xeb, 0xd2, 0x07, + 0x1b, 0x7c, 0x5e, 0xed, 0xd6, 0xe7, 0xe5, 0xf9, + 0xc1, 0x0e, 0x47, 0xd4, 0x4c, 0xab, 0x8c, 0xf0, + 0xe8, 0xee, 0x8b, 0x40, 0x36, 0x35, 0x58, 0x8f, + 0xf4, 0x6f, 0xfc, 0xfd, 0x0f, 0xdd, 0x55, 0x8b, + 0x45, 0x8c, 0xf0, 0x47, 0xdc, 0xb4, 0xac, 0x21, + 0x3b, 0x4b, 0x20, 0xe6, 0x81, 0xb3, 0xcc, 0x90, + 0xd4, 0x5e, 0xf1, 0xa4, 0x9b, 0x68, 0x52, 0xc8, + 0xf1, 0x2d, 0xf9, 0xc4, 0x77, 0xc6, 0x4d, 0xa9, + 0x90, 0xc7, 0x10, 0xfd, 0x43, 0xc8, 0x4b, 0x6b, + 0x23, 0x5e, 0x92, 0xf5, 0x8f, 0xac, 0xd5, 0x7d, + 0x60, 0x27, 0x36, 0x7c, 0x21, 0x4e, 0x21, 0x99, + 0xde, 0xcb, 0xc0, 0x45, 0xf3, 0x04, 0x22, 0xb8, + 0x7d, 0x16, 0x68, 0x40, 0xf9, 0x5c, 0xf0, 0xb9, + 0x7e, 0x8c, 0x05, 0xb6, 0xfc, 0x28, 0xbb, 0x3d, + 0xd8, 0xff, 0xb6, 0xa4, 0xd4, 0x54, 0x27, 0x3b, + 0x1a, 0x42, 0x4e, 0xf5, 0xa6, 0xa8, 0x5e, 0x44, + 0xe2, 0x9e, 0xed, 0x68, 0x6a, 0x27, 0x60, 0x13, + 0x8d, 0x2f, 0x27, 0x70, 0xcd, 0x57, 0xc9, 0x18, + 0xa3, 0xb0, 0x30, 0xa1, 0xf4, 0xe6, 0x32, 0x12, + 0x89, 0x2a, 0xaf, 0x40, 0xa5, 0xfd, 0x52, 0xf1, + 0xaa, 0x8a, 0xa4, 0xef, 0x20, 0x3d, 0x10, 0xa3, + 0x70, 0xf2, 0x39, 0xc5, 0x05, 0x99, 0x22, 0x10, + 0x81, 0x83, 0x6e, 0x45, 0xa4, 0xf3, 0x5a, 0x9d, + 0x6a, 0xb8, 0x88, 0xfe, 0x69, 0x40, 0xd1, 0xb1, + 0xcb, 0x2a, 0xdb, 0x28, 0x05, 0xde, 0x54, 0xbf, + 0x3d, 0x86, 0x5f, 0x39, 0x8b, 0xc1, 0xf4, 0xaf, + 0x00, 0x61, 0x86, 0x01, 0xfa, 0x22, 0xac, 0xf6, + 0x2c, 0xa4, 0x17, 0x6a, 0xa7, 0xd8, 0x0a, 0x8c, + 0x9f, 0xbf, 0x1f, 0x62, 0xb2, 0x2e, 0x68, 0x52, + 0x3f, 0x82, 0x8f, 0xe5, 0x28, 0x4d, 0xdb, 0xb5, + 0x5a, 0x96, 0x28, 0x27, 0x19, 0xaf, 0x43, 0xb9]) + +KNOWN_KEYS = {APL_INTEL_PROD_KEY: 'APL Intel prod key', + CNL_INTEL_PROD_KEY: 'CNL Intel prod key', + ICL_INTEL_PROD_KEY: 'ICL Intel prod key', + TGL_INTEL_PROD_KEY: 'TGL Intel prod key', + COMMUNITY_KEY: 'Community key'} + + +def parse_params(): + """ Parses parameters + """ + parser = argparse.ArgumentParser(description='SOF Binary Info Utility') + parser.add_argument('-v', '--verbose', help='increase output verbosity', + action='store_true') + parser.add_argument('--headers', help='display headers only', + action='store_true') + parser.add_argument('--full_bytes', help='display full byte arrays', + action='store_true') + parser.add_argument('--no_colors', help='disable colors in output', + action='store_true') + parser.add_argument('--no_cse', help='disable cse manifest parsing', + action='store_true') + parser.add_argument('--no_headers', help='skip information about headers', + action='store_true') + parser.add_argument('--no_modules', help='skip information about modules', + action='store_true') + parser.add_argument('--no_memory', help='skip information about memory', + action='store_true') + parser.add_argument('--valid', help='is ri signed by Intel production key', + action='store_true') + parser.add_argument('sof_ri_path', help='path to fw binary file to parse') + parsed_args = parser.parse_args() + + return parsed_args + +# Helper Functions + + +def change_color(color): + """ Prints escape code to change text color + """ + color_code = {'red': 91, 'green': 92, 'yellow': 93, 'blue': 94, + 'magenta': 95, 'cyan': 96, 'white': 98, 'none': 0} + return '\033[{}m'.format(color_code[color]) + + +def uint_to_string(uint, both=False): + """ Prints uint in readable form + """ + if both: + return hex(uint) + ' (' + repr(uint) + ')' + return hex(uint) + + +def date_to_string(date): + """ Prints BCD date in readable form + """ + return date[2:6]+'/'+date[6:8]+'/'+date[8:10] + + +def chararr_to_string(chararr, max_len): + """ Prints array of characters (null terminated or till max_len) + in readable form + """ + out = '' + for i in range(0, max_len): + if chararr[i] == 0: + return out + out += '{:c}'.format(chararr[i]) + return out + + +def mod_type_to_string(mod_type): + """ Prints module type in readable form + """ + out = '(' + # type + if (mod_type & 0xf) == 0: + out += ' builtin' + elif (mod_type & 0xf) == 1: + out += ' loadable' + # Module that may be instantiated by fw on startup + if ((mod_type >> 4) & 0x1) == 1: + out += ' auto_start' + # Module designed to run with low latency scheduler + if ((mod_type >> 5) & 0x1) == 1: + out += ' LL' + # Module designed to run with edf scheduler + if ((mod_type >> 6) & 0x1) == 1: + out += ' DP' + out += ' )' + return out + + +def seg_flags_to_string(flags): + """ Prints module segment flags in readable form + """ + out = '(' + if flags & 0x1 == 0x1: + out = out + ' contents' + if flags & 0x2 == 0x2: + out = out + ' alloc' + if flags & 0x4 == 0x4: + out = out + ' load' + if flags & 0x8 == 0x8: + out = out + ' readonly' + if flags & 0x10 == 0x10: + out = out + ' code' + if flags & 0x20 == 0x20: + out = out + ' data' + out = out + ' type=' + repr((flags >> 8) & 0xf) + out = out + ' pages=' + repr((flags >> 16) & 0xffff) + out = out + ' )' + return out + +# Parsers + + +def parse_extended_manifest_ae1(reader): + ext_mft = ExtendedManifestAE1() + hdr = Component('ext_mft_hdr', 'Header', 0) + ext_mft.add_comp(hdr) + + sig = reader.read_string(4) + reader.info('Extended Manifest (' + sig + ')', -4) + hdr.add_a(Astring('sig', sig)) + + # Next dword is the total length of the extended manifest + # (need to use it for further parsing) + reader.ext_mft_length = reader.read_dw() + hdr.add_a(Auint('length', reader.ext_mft_length)) + hdr.add_a(Astring('ver', '{}.{}'.format(reader.read_w(), reader.read_w()))) + hdr.add_a(Auint('entries', reader.read_dw())) + + reader.ff_data(reader.ext_mft_length-16) + return ext_mft + + +def parse_extended_manifest_xman(reader): + ext_mft = ExtendedManifestXMan() + hdr = Component('ext_mft_hdr', 'Header', 0) + ext_mft.add_comp(hdr) + + sig = reader.read_string(4) + reader.info('Extended Manifest (' + sig + ')', -4) + hdr.add_a(Astring('sig', sig)) + + # Next dword is the total length of the extended manifest + # (need to use it for further parsing) + reader.ext_mft_length = reader.read_dw() + hdr_length = reader.read_dw() + hdr_ver = reader.read_dw() + + major = hdr_ver >> 24 + minor = (hdr_ver >> 12) & 0xFFF + patch = hdr_ver & 0xFFF + + hdr.add_a(Auint('length', reader.ext_mft_length)) + hdr.add_a(Astring('ver', '{}.{}.{}'.format(major, minor, patch))) + hdr.add_a(Auint('hdr_length', hdr_length)) + + reader.ff_data(reader.ext_mft_length-16) + return ext_mft + + +def parse_extended_manifest(reader): + """ Parses extended manifest from sof binary + """ + + reader.info('Looking for Extended Manifest') + # Try to detect signature first + sig = reader.read_string(4) + reader.set_offset(0) + if sig == '$AE1': + ext_mft = parse_extended_manifest_ae1(reader) + elif sig == 'XMan': + ext_mft = parse_extended_manifest_xman(reader) + else: + ext_mft = ExtendedManifestAE1() + hdr = Component('ext_mft_hdr', 'Header', 0) + ext_mft.add_comp(hdr) + reader.info('info: Extended Manifest not found (sig = '+sig+')') + reader.ext_mft_length = 0 + hdr.add_a(Auint('length', reader.ext_mft_length)) + + return ext_mft + + +def parse_cse_manifest(reader): + """ Parses CSE manifest form sof binary + """ + reader.info('Looking for CSE Manifest') + cse_mft = CseManifest(reader.get_offset()) + + # Try to detect signature first + sig = reader.read_string(4) + if sig != '$CPD': + reader.error('CSE Manifest NOT found ' + sig + ')', -4) + sys.exit(1) + reader.info('CSE Manifest (' + sig + ')', -4) + + # Read the header + hdr = Component('cse_mft_hdr', 'Header', reader.get_offset()) + cse_mft.add_comp(hdr) + hdr.add_a(Astring('sig', sig)) + # read number of entries + nb_entries = reader.read_dw() + reader.info('# of entries {}'.format(nb_entries)) + hdr.add_a(Adec('nb_entries', nb_entries)) + # read version (1byte for header ver and 1 byte for entry ver) + ver = reader.read_w() + hdr.add_a(Ahex('header_version', ver)) + header_length = reader.read_b() + hdr.add_a(Ahex('header_length', header_length)) + hdr.add_a(Ahex('checksum', reader.read_b())) + hdr.add_a(Astring('partition_name', reader.read_string(4))) + + reader.set_offset(cse_mft.file_offset + header_length) + # Read entries + nb_index = 0 + while nb_index < nb_entries: + reader.info('Looking for CSE Manifest entry') + entry_name = reader.read_string(12) + entry_offset = reader.read_dw() + entry_length = reader.read_dw() + # reserved field + reader.read_dw() + + hdr_entry = Component('cse_hdr_entry', 'Entry', reader.get_offset()) + hdr_entry.add_a(Astring('entry_name', entry_name)) + hdr_entry.add_a(Ahex('entry_offset', entry_offset)) + hdr_entry.add_a(Ahex('entry_length', entry_length)) + hdr.add_comp(hdr_entry) + + reader.info('CSE Entry name {} length {}'.format(entry_name, + entry_length)) + + if '.man' in entry_name: + entry = CssManifest(entry_name, + reader.ext_mft_length + entry_offset) + cur_off = reader.set_offset(reader.ext_mft_length + entry_offset) + parse_css_manifest(entry, reader, + reader.ext_mft_length + entry_offset + entry_length) # noqa: 501 + reader.set_offset(cur_off) + elif '.met' in entry_name: + cur_off = reader.set_offset(reader.ext_mft_length + entry_offset) + entry = parse_mft_extension(reader, 0) + entry.name = '{} ({})'.format(entry_name, entry.name) + reader.set_offset(cur_off) + else: + # indicate the place, the entry is enumerated. mft parsed later + entry = Component('adsp_mft_cse_entry', entry_name, entry_offset) + cse_mft.add_comp(entry) + + nb_index += 1 + + return cse_mft + + +def parse_css_manifest(css_mft, reader, limit): + """ Parses CSS manifest from sof binary + """ + reader.info('Parsing CSS Manifest') + ver, = struct.unpack('I', reader.get_data(0, 4)) + if ver == 4: + reader.info('CSS Manifest type 4') + return parse_css_manifest_4(css_mft, reader, limit) + + reader.error('CSS Manifest NOT found or NOT recognized!') + sys.exit(1) + + +def parse_css_manifest_4(css_mft, reader, size_limit): + """ Parses CSS manifest type 4 from sof binary + """ + + reader.info('Parsing CSS Manifest type 4') + # CSS Header + hdr = Component('css_mft_hdr', 'Header', reader.get_offset()) + css_mft.add_comp(hdr) + + hdr.add_a(Auint('type', reader.read_dw())) + header_len_dw = reader.read_dw() + hdr.add_a(Auint('header_len_dw', header_len_dw)) + hdr.add_a(Auint('header_version', reader.read_dw())) + hdr.add_a(Auint('reserved0', reader.read_dw(), 'red')) + hdr.add_a(Ahex('mod_vendor', reader.read_dw())) + hdr.add_a(Adate('date', hex(reader.read_dw()))) + size = reader.read_dw() + hdr.add_a(Auint('size', size)) + hdr.add_a(Astring('header_id', reader.read_string(4))) + hdr.add_a(Auint('padding', reader.read_dw())) + hdr.add_a(Aversion('fw_version', reader.read_w(), reader.read_w(), + reader.read_w(), reader.read_w())) + hdr.add_a(Auint('svn', reader.read_dw())) + reader.read_bytes(18*4) + modulus_size = reader.read_dw() + hdr.add_a(Adec('modulus_size', modulus_size)) + exponent_size = reader.read_dw() + hdr.add_a(Adec('exponent_size', exponent_size)) + modulus = reader.read_bytes(modulus_size * 4) + hdr.add_a(Amodulus('modulus', modulus, KNOWN_KEYS.get(modulus, 'Other'))) + hdr.add_a(Abytes('exponent', reader.read_bytes(exponent_size * 4))) + hdr.add_a(Abytes('signature', reader.read_bytes(modulus_size * 4))) + + # Move right after the header + reader.set_offset(css_mft.file_offset + header_len_dw*4) + + # Anything packed here is + # either an 'Extension' beginning with + # dw0 - extension type + # dw1 - extension length (in bytes) + # that could be parsed if extension type is recognized + # + # or series of 0xffffffff that should be skipped + reader.info( + 'Parsing CSS Manifest extensions end 0x{:x}'.format(size_limit)) + ext_idx = 0 + while reader.get_offset() < size_limit: + ext_type = reader.read_dw() + reader.info('Reading extension type 0x{:x}'.format(ext_type)) + if ext_type == 0xffffffff: + continue + reader.set_offset(reader.get_offset() - 4) + css_mft.add_comp(parse_mft_extension(reader, ext_idx)) + ext_idx += 1 + + return css_mft + + +def parse_mft_extension(reader, ext_id): + """ Parses mft extension from sof binary + """ + ext_type = reader.read_dw() + ext_len = reader.read_dw() + if ext_type == 15: + begin_off = reader.get_offset() + ext = PlatFwAuthExtension(ext_id, reader.get_offset()-8) + ext.add_a(Astring('name', reader.read_string(4))) + ext.add_a(Auint('vcn', reader.read_dw())) + ext.add_a(Abytes('bitmap', reader.read_bytes(16), 'red')) + ext.add_a(Auint('svn', reader.read_dw())) + read_len = reader.get_offset() - begin_off + reader.ff_data(ext_len - read_len) + elif ext_type == 17: + ext = AdspMetadataFileExt(ext_id, reader.get_offset()-8) + ext.add_a(Auint('adsp_imr_type', reader.read_dw(), 'red')) + # skip reserved part + reader.read_bytes(16) + reader.read_dw() + reader.read_dw() + # + ext.add_a(Auint('version', reader.read_dw())) + ext.add_a(Abytes('sha_hash', reader.read_bytes(32))) + ext.add_a(Auint('base_offset', reader.read_dw())) + ext.add_a(Auint('limit_offset', reader.read_dw())) + ext.add_a(Abytes('attributes', reader.read_bytes(16))) + else: + ext = MftExtension(ext_id, 'Other Extension', reader.get_offset()-8) + reader.ff_data(ext_len-8) + ext.add_a(Auint('type', ext_type)) + ext.add_a(Auint('length', ext_len)) + return ext + + +def parse_adsp_manifest_hdr(reader): + """ Parses ADSP manifest hader from sof binary + """ + # Verify signature + try: + sig = reader.read_string(4) + except UnicodeDecodeError: + print('\n' + reader.offset_to_string() + + '\terror: Failed to decode signature, wrong position?') + sys.exit(1) + if sig != '$AM1': + reader.error('ADSP Manifest NOT found!', -4) + sys.exit(1) + reader.info('ADSP Manifest (' + sig + ')', -4) + + hdr = Component('adsp_mft_hdr', 'ADSP Manifest Header', + reader.get_offset() - 4) + hdr.add_a(Astring('sig', sig)) + + hdr.add_a(Auint('size', reader.read_dw())) + hdr.add_a(Astring('name', chararr_to_string(reader.read_bytes(8), 8))) + hdr.add_a(Auint('preload', reader.read_dw())) + hdr.add_a(Auint('fw_image_flags', reader.read_dw())) + hdr.add_a(Auint('feature_mask', reader.read_dw())) + hdr.add_a(Aversion('build_version', reader.read_w(), reader.read_w(), + reader.read_w(), reader.read_w())) + + hdr.add_a(Adec('num_module_entries', reader.read_dw())) + hdr.add_a(Ahex('hw_buf_base_addr', reader.read_dw())) + hdr.add_a(Auint('hw_buf_length', reader.read_dw())) + hdr.add_a(Ahex('load_offset', reader.read_dw())) + + return hdr + + +def parse_adsp_manifest_mod_entry(index, reader): + """ Parses ADSP manifest module entry from sof binary + """ + # Verify Mod Entry signature + try: + sig = reader.read_string(4) + except UnicodeDecodeError: + print(reader.offset_to_string() + + '\terror: Failed to decode ModuleEntry signature') + sys.exit(1) + if sig != '$AME': + reader.error('ModuleEntry signature NOT found!') + sys.exit(1) + reader.info('Module Entry signature found (' + sig + ')', -4) + + mod = AdspModuleEntry('mod_entry_'+repr(index), + reader.get_offset() - 4) + mod.add_a(Astring('sig', sig)) + + mod.add_a(Astring('mod_name', + chararr_to_string(reader.read_bytes(8), 8))) + mod.add_a(Astring('uuid', reader.read_uuid())) + me_type = reader.read_dw() + mod.add_a(Astring('type', + hex(me_type) + ' ' + mod_type_to_string(me_type))) + mod.add_a(Abytes('hash', reader.read_bytes(32))) + mod.add_a(Ahex('entry_point', reader.read_dw())) + mod.add_a(Adec('cfg_offset', reader.read_w())) + mod.add_a(Adec('cfg_count', reader.read_w())) + mod.add_a(Auint('affinity_mask', reader.read_dw())) + mod.add_a(Adec('instance_max_count', reader.read_w())) + mod.add_a(Auint('instance_stack_size', reader.read_w())) + for i in range(0, 3): + seg_flags = reader.read_dw() + mod.add_a(Astring('seg_'+repr(i)+'_flags', + hex(seg_flags) + ' ' + seg_flags_to_string(seg_flags))) # noqa: 501 + mod.add_a(Ahex('seg_'+repr(i)+'_v_base_addr', reader.read_dw())) + mod.add_a(Ahex('seg_'+repr(i)+'_size', + ((seg_flags >> 16) & 0xffff)*0x1000)) + mod.add_a(Ahex('seg_'+repr(i)+'_file_offset', reader.read_dw())) + + return mod + + +def parse_adsp_manifest(reader, name): + """ Parses ADSP manifest from sof binary + """ + adsp_mft = AdspManifest(name, reader.get_offset()) + adsp_mft.add_comp(parse_adsp_manifest_hdr(reader)) + num_module_entries = adsp_mft.cdir['adsp_mft_hdr'].adir['num_module_entries'].val # noqa: 501 + for i in range(0, num_module_entries): + mod_entry = parse_adsp_manifest_mod_entry(i, reader) + adsp_mft.add_comp(mod_entry) + + return adsp_mft + + +def parse_fw_bin(path, no_cse, verbose): + """ Parses sof binary + """ + reader = BinReader(path, verbose) + + parsed_bin = FwBin() + parsed_bin.add_a(Astring('file_name', reader.file_name)) + parsed_bin.add_a(Auint('file_size', reader.file_size)) + parsed_bin.add_comp(parse_extended_manifest(reader)) + if not no_cse: + parsed_bin.add_comp(parse_cse_manifest(reader)) + reader.set_offset(reader.ext_mft_length + 0x2000) + parsed_bin.add_comp(parse_adsp_manifest(reader, 'cavs0015')) + + reader.info('Parsing finished', show_offset=False) + return parsed_bin + + +class BinReader(): + """ sof binary reader + """ + + def __init__(self, path, verbose): + self.verbose = verbose + self.cur_offset = 0 + self.ext_mft_length = 0 + self.info('Reading SOF ri image ' + path, show_offset=False) + self.file_name = path + # read the content + self.data = open(path, 'rb').read() + self.file_size = len(self.data) + self.info('File size ' + uint_to_string(self.file_size, True), + show_offset=False) + + def get_offset(self): + """ Retrieve the offset, the reader is at + """ + return self.cur_offset + + def ff_data(self, delta_offset): + """ Forwards the read pointer by specified number of bytes + """ + self.cur_offset += delta_offset + + def set_offset(self, offset): + """ Set current reader offset + """ + old_offset = self.cur_offset + self.cur_offset = offset + return old_offset + + def get_data(self, beg, length): + """ Retrieves the data from beg to beg+length. + This one is good to peek the data w/o advancing the read pointer + """ + return self.data[self.cur_offset + beg: self.cur_offset + beg + length] + + def read_bytes(self, count): + """ Reads the specified number of bytes from the stream + """ + bts = self.get_data(0, count) + self.ff_data(count) + return bts + + def read_dw(self): + """ Reads a dword from the stream + """ + dword, = struct.unpack('I', self.get_data(0, 4)) + self.ff_data(4) + return dword + + def read_w(self): + """ Reads a word from the stream + """ + word, = struct.unpack('H', self.get_data(0, 2)) + self.ff_data(2) + return word + + def read_b(self): + """ Reads a byte from the stream + """ + byte, = struct.unpack('B', self.get_data(0, 1)) + self.ff_data(1) + return byte + + def read_string(self, size_in_file): + """ Reads a string from the stream, potentially padded with zeroes + """ + return self.read_bytes(size_in_file).decode().rstrip('\0') + + def read_uuid(self): + """ Reads a UUID from the stream and returns as string + """ + out = '{:08x}'.format(self.read_dw()) + out += '-'+'{:04x}'.format(self.read_w()) + out += '-'+'{:04x}'.format(self.read_w()) + out += '-'+'{:02x}'.format(self.read_b()) + \ + '{:02x}'.format(self.read_b()) + '-' + for _ in range(0, 6): + out += '{:02x}'.format(self.read_b()) + return out + + def offset_to_string(self, delta=0): + """ Retrieves readable representation of the current offset value + """ + return uint_to_string(self.cur_offset+delta) + + def info(self, loginfo, off_delta=0, verb_info=True, show_offset=True): + """ Prints 'info' log to the output, respects verbose mode + """ + if verb_info and not self.verbose: + return + if show_offset: + print(self.offset_to_string(off_delta) + '\t' + loginfo) + else: + print(loginfo) + + def error(self, logerror, off_delta=0): + """ Prints 'error' log to the output + """ + print(self.offset_to_string(off_delta) + '\terror: ' + logerror) + +# Data Model + + +class Attribute(): + """ Attribute: base class with global formatting options + """ + no_colors = False + full_bytes = True + + +class Auint(Attribute): + """ Attribute : unsigned integer + """ + + def __init__(self, name, val, color='none'): + self.name = name + self.val = val + self.color = color + + def __str__(self): + if Attribute.no_colors: + return uint_to_string(self.val) + return '{}{}{}'.format(change_color(self.color), + uint_to_string(self.val), + change_color('none')) + + +class Ahex(Attribute): + """ Attribute : unsigned integer printed as hex + """ + + def __init__(self, name, val, color='none'): + self.name = name + self.val = val + self.color = color + + def __str__(self): + if Attribute.no_colors: + return hex(self.val) + return '{}{}{}'.format(change_color(self.color), hex(self.val), + change_color('none')) + + +class Adec(Attribute): + """ Attribute: integer printed as dec + """ + + def __init__(self, name, val): + self.name = name + self.val = val + + def __str__(self): + return repr(self.val) + + +class Abytes(Attribute): + """ Attribute: array of bytes + """ + + def __init__(self, name, val, color='none'): + self.name = name + self.val = val + self.color = color + + def __str__(self): + length = len(self.val) + if Attribute.no_colors: + out = '' + else: + out = '{}'.format(change_color(self.color)) + if Attribute.full_bytes or length <= 16: + out += ' '.join(['{:02x}'.format(b) for b in self.val]) + else: + out += ' '.join('{:02x}'.format(b) for b in self.val[:8]) + out += ' ... ' + out += ' '.join('{:02x}'.format(b) + for b in self.val[length-8:length]) + if not Attribute.no_colors: + out += '{}'.format(change_color('none')) + return out + + +class Adate(Attribute): + """ Attribute: Date in BCD format + """ + + def __init__(self, name, val): + self.name = name + self.val = val + + def __str__(self): + return date_to_string(self.val) + + +class Astring(Attribute): + """ Attribute: String + """ + + def __init__(self, name, val): + self.name = name + self.val = val + + def __str__(self): + return self.val + + +class Aversion(Attribute): + """ Attribute: version + """ + + def __init__(self, name, major, minor, hotfix, build): + self.name = name + self.val = '{:d}.{:d}.{:d}.{:d}'.format(major, minor, hotfix, build) + + def __str__(self): + return self.val + + +class Amodulus(Abytes): + """ Attribute: modulus from RSA public key + """ + + def __init__(self, name, val, val_type): + super().__init__(name, val) + self.val_type = val_type + + def __str__(self): + out = super().__str__() + if not Attribute.full_bytes: + if Attribute.no_colors: + out += ' ({})'.format(self.val_type) + else: + out += ' {}({}){}'.format(change_color('red'), self.val_type, + change_color('none')) + return out + + +class Component(): + """ A component of sof binary + """ + + def __init__(self, uid, name, file_offset): + self.uid = uid + self.name = name + self.file_offset = file_offset + self.attribs = [] + self.adir = {} + self.max_attr_name_len = 0 + self.components = [] + self.cdir = {} + + def add_a(self, attrib): + """ Adds an attribute + """ + self.max_attr_name_len = max(self.max_attr_name_len, + len(attrib.name)) + self.attribs.append(attrib) + self.adir[attrib.name] = attrib + + def add_comp(self, comp): + """ Adds a nested component + """ + self.components.append(comp) + self.cdir[comp.uid] = comp + + def get_comp(self, comp_uid): + """ Retrieves a nested component by id + """ + for comp in self.components: + if comp.uid == comp_uid: + return comp + return None + + def dump_info(self, pref, comp_filter): + """ Prints out the content (name, all attributes, and nested comps) + """ + print(pref + self.name) + for attrib in self.attribs: + print("{:} {:<{:}} {:}".format(pref, attrib.name, + self.max_attr_name_len, attrib)) + self.dump_comp_info(pref, comp_filter) + + def dump_attrib_info(self, pref, attr_name): + """ Prints out a single attribute + """ + attrib = self.adir[attr_name] + print("{:} {:<{:}} {:}".format(pref, attrib.name, + self.max_attr_name_len, attrib)) + + def dump_comp_info(self, pref, comp_filter=''): + """ Prints out all nested components (filtered by name set to 'filter') + """ + for comp in self.components: + if comp.name in comp_filter: + continue + print() + comp.dump_info(pref + ' ', comp_filter) + + def add_comp_to_mem_map(self, mem_map): + for comp in self.components: + comp.add_comp_to_mem_map(mem_map) + + +class ExtendedManifestAE1(Component): + """ Extended manifest + """ + + def __init__(self): + super(ExtendedManifestAE1, self).__init__('ext_mft', + 'Extended Manifest', 0) + + def dump_info(self, pref, comp_filter): + hdr = self.cdir['ext_mft_hdr'] + if hdr.adir['length'].val == 0: + return + out = '{}{}'.format(pref, self.name) + out += ' ver {}'.format(hdr.adir['ver']) + out += ' entries {}'.format(hdr.adir['entries']) + print(out) + self.dump_comp_info(pref, comp_filter + ['Header']) + + +class ExtendedManifestXMan(Component): + """ Extended manifest + """ + + def __init__(self): + super(ExtendedManifestXMan, self).__init__('ext_mft', + 'Extended Manifest', 0) + + def dump_info(self, pref, comp_filter): + hdr = self.cdir['ext_mft_hdr'] + if hdr.adir['length'].val == 0: + return + out = '{}{}'.format(pref, self.name) + out += ' ver {}'.format(hdr.adir['ver']) + out += ' length {}'.format(hdr.adir['length'].val) + print(out) + self.dump_comp_info(pref, comp_filter + ['Header']) + + +class CseManifest(Component): + """ CSE Manifest + """ + + def __init__(self, offset): + super(CseManifest, self).__init__('cse_mft', 'CSE Manifest', offset) + + def dump_info(self, pref, comp_filter): + hdr = self.cdir['cse_mft_hdr'] + print('{}{} ver {} checksum {} partition name {}'. + format(pref, + self.name, hdr.adir['header_version'], + hdr.adir['checksum'], hdr.adir['partition_name'])) + self.dump_comp_info(pref, comp_filter + ['Header']) + + +class CssManifest(Component): + """ CSS Manifest + """ + + def __init__(self, name, offset): + super(CssManifest, self).__init__('css_mft', name, offset) + + def dump_info(self, pref, comp_filter): + hdr = self.cdir['css_mft_hdr'] + out = '{}{} (CSS Manifest)'.format(pref, self.name) + out += ' type {}'.format(hdr.adir['type']) + out += ' ver {}'.format(hdr.adir['header_version']) + out += ' date {}'.format(hdr.adir['date']) + print(out) + print('{} Rsvd0 {}'. + format(pref, hdr.adir['reserved0'])) + print('{} Modulus size (dwords) {}'. + format(pref, hdr.adir['modulus_size'])) + print('{} {}'.format(pref, hdr.adir['modulus'])) + print('{} Exponent size (dwords) {}'. + format(pref, + hdr.adir['exponent_size'])) + print('{} {}'.format(pref, hdr.adir['exponent'])) + print('{} Signature'.format(pref)) + print('{} {}'.format(pref, hdr.adir['signature'])) + # super().dump_info(pref) + self.dump_comp_info(pref, comp_filter + ['Header']) + + +class MftExtension(Component): + """ Manifest Extension + """ + + def __init__(self, ext_id, name, offset): + super(MftExtension, self).__init__('mft_ext'+repr(ext_id), name, + offset) + + def dump_info(self, pref, comp_filter): + print('{}{} type {} length {}'. + format(pref, self.name, + self.adir['type'], self.adir['length'])) + + +class PlatFwAuthExtension(MftExtension): + """ Platform FW Auth Extension + """ + + def __init__(self, ext_id, offset): + super(PlatFwAuthExtension, + self).__init__(ext_id, 'Plat Fw Auth Extension', offset) + + def dump_info(self, pref, comp_filter): + out = '{}{}'.format(pref, self.name) + out += ' name {}'.format(self.adir['name']) + out += ' vcn {}'.format(self.adir['vcn']) + out += ' bitmap {}'.format(self.adir['bitmap']) + out += ' svn {}'.format(self.adir['svn']) + print(out) + + +class AdspMetadataFileExt(MftExtension): + """ ADSP Metadata File Extension + """ + + def __init__(self, ext_id, offset): + super(AdspMetadataFileExt, + self).__init__(ext_id, 'ADSP Metadata File Extension', + offset) + + def dump_info(self, pref, comp_filter): + out = '{}{}'.format(pref, self.name) + out += ' ver {}'.format(self.adir['version']) + out += ' base offset {}'.format(self.adir['base_offset']) + out += ' limit offset {}'.format(self.adir['limit_offset']) + print(out) + print('{} IMR type {}'.format(pref, self.adir['adsp_imr_type'])) + print('{} Attributes'.format(pref)) + print('{} {}'.format(pref, self.adir['attributes'])) + + +class AdspManifest(Component): + """ ADSP Manifest + """ + + def __init__(self, name, offset): + super(AdspManifest, self).__init__('adsp_mft', name, offset) + + def dump_info(self, pref, comp_filter): + hdr = self.cdir['adsp_mft_hdr'] + out = '{}{} (ADSP Manifest)'.format(pref, self.name) + out += ' name {}'.format(hdr.adir['name']) + out += ' build ver {}'.format(hdr.adir['build_version']) + out += ' feature mask {}'.format(hdr.adir['feature_mask']) + out += ' image flags {}'.format(hdr.adir['fw_image_flags']) + print(out) + print('{} HW buffers base address {} length {}'. + format(pref, + hdr.adir['hw_buf_base_addr'], + hdr.adir['hw_buf_length'])) + print('{} Load offset {}'.format(pref, + hdr.adir['load_offset'])) + self.dump_comp_info(pref, comp_filter + ['ADSP Manifest Header']) + + +class AdspModuleEntry(Component): + """ ADSP Module Entry + """ + + def __init__(self, uid, offset): + super(AdspModuleEntry, self).__init__(uid, 'Module Entry', offset) + + def dump_info(self, pref, comp_filter): + print('{}{:9} {}'.format(pref, str(self.adir['mod_name']), + self.adir['uuid'])) + print('{} entry point {} type {}'.format(pref, self.adir['entry_point'], # noqa: 501 + self.adir['type'])) + out = '{} cfg offset {} count {} affinity {}'.format(pref, + self.adir['cfg_offset'], self.adir['cfg_count'], # noqa: 501 + self.adir['affinity_mask']) # noqa: 501 + out += ' instance max count {} stack size {}'.format( + self.adir['instance_max_count'], self.adir['instance_stack_size']) + print(out) + print('{} .text {} file offset {} flags {}'.format(pref, + self.adir['seg_0_v_base_addr'], self.adir['seg_0_file_offset'], # noqa: 501 + self.adir['seg_0_flags'])) # noqa: 501 + print('{} .rodata {} file offset {} flags {}'.format(pref, + self.adir['seg_1_v_base_addr'], self.adir['seg_1_file_offset'], # noqa: 501 + self.adir['seg_1_flags'])) # noqa: 501 + print('{} .bss {} file offset {} flags {}'.format(pref, + self.adir['seg_2_v_base_addr'], self.adir['seg_2_file_offset'], # noqa: 501 + self.adir['seg_2_flags'])) # noqa: 501 + + def add_comp_to_mem_map(self, mem_map): + mem_map.insert_segment(DspMemorySegment( + self.adir['mod_name'].val + '.text', + self.adir['seg_0_v_base_addr'].val, + self.adir['seg_0_size'].val)) + mem_map.insert_segment(DspMemorySegment( + self.adir['mod_name'].val + '.rodata', + self.adir['seg_1_v_base_addr'].val, + self.adir['seg_1_size'].val)) + mem_map.insert_segment(DspMemorySegment( + self.adir['mod_name'].val + '.bss', + self.adir['seg_2_v_base_addr'].val, + self.adir['seg_2_size'].val)) + + +class FwBin(Component): + """ Parsed sof binary + """ + + def __init__(self): + super(FwBin, self).__init__('bin', 'SOF Binary', 0) + + def dump_info(self, pref, comp_filter): + """ Print out the content + """ + print('SOF Binary {} size {}'.format( + self.adir['file_name'], self.adir['file_size'])) + self.dump_comp_info(pref, comp_filter) + + def populate_mem_map(self, mem_map): + """ Adds modules' segments to the memory map + """ + self.add_comp_to_mem_map(mem_map) + +# DSP Memory Layout + + +def get_mem_map(ri_path): + """ Retrieves memory map for platform determined by the file name + """ + for plat_name in DSP_MEM_SPACE_EXT: + if plat_name in ri_path: + return DSP_MEM_SPACE_EXT[plat_name] + return DspMemory('Memory layout undefined', []) + + +def add_lmap_mem_info(ri_path, mem_map): + """ Optional lmap processing + """ + lmap_path = ri_path[0:ri_path.rfind('.')] + '.lmap' + try: + with open(lmap_path) as lmap: + it_lines = iter(lmap.readlines()) + for line in it_lines: + if 'Sections:' in line: + next(it_lines) + break + for line in it_lines: + tok = line.split() + mem_map.insert_segment(DspMemorySegment(tok[1], + int(tok[3], 16), int(tok[2], 16))) # noqa: 501 + next(it_lines) + + except FileNotFoundError: + return + + +class DspMemorySegment(object): + """ Single continuous memory space + """ + + def __init__(self, name, base_address, size): + self.name = name + self.base_address = base_address + self.size = size + self.used_size = 0 + self.inner_segments = [] + + def is_inner(self, segment): + return self.base_address <= segment.base_address and \ + segment.base_address + segment.size <= self.base_address + self.size # noqa: 501 + + def insert_segment(self, segment): + for seg in self.inner_segments: + if seg.is_inner(segment): + seg.insert_segment(segment) + return + self.inner_segments.append(segment) + self.used_size += segment.size + + def dump_info(self, pref): + free_size = self.size - self.used_size + out = '{}{:<35} 0x{:x}'.format(pref, self.name, self.base_address) + if self.used_size > 0: + out += ' ({} + {} {:.2f}% used)'.format(self.used_size, free_size, + self.used_size*100/self.size) # noqa: 501 + else: + out += ' ({})'.format(free_size) + print(out) + for seg in self.inner_segments: + seg.dump_info(pref + ' ') + + +class DspMemory(object): + """ Dsp Memory, all top-level segments + """ + + def __init__(self, platform_name, segments): + self.platform_name = platform_name + self.segments = segments + + def insert_segment(self, segment): + """ Inserts segment + """ + for seg in self.segments: + if seg.is_inner(segment): + seg.insert_segment(segment) + return + + def dump_info(self): + print(self.platform_name) + for seg in self.segments: + seg.dump_info(' ') + +# Layouts of DSP memory for known platforms + + +APL_MEMORY_SPACE = DspMemory('Intel Apollolake', + [ + DspMemorySegment( + 'imr', 0xa0000000, 4*1024*1024), + DspMemorySegment( + 'l2 hpsram', 0xbe000000, 8*64*1024), + DspMemorySegment( + 'l2 lpsram', 0xbe800000, 2*64*1024) + ]) + +CNL_MEMORY_SPACE = DspMemory('Intel Cannonlake', + [ + DspMemorySegment( + 'imr', 0xb0000000, 8*0x1024*0x1024), + DspMemorySegment( + 'l2 hpsram', 0xbe000000, 48*64*1024), + DspMemorySegment( + 'l2 lpsram', 0xbe800000, 1*64*1024) + ]) + +ICL_MEMORY_SPACE = DspMemory('Intel Icelake', + [ + DspMemorySegment( + 'imr', 0xb0000000, 8*1024*1024), + DspMemorySegment( + 'l2 hpsram', 0xbe000000, 47*64*1024), + DspMemorySegment( + 'l2 lpsram', 0xbe800000, 1*64*1024) + ]) + +TGL_MEMORY_SPACE = DspMemory('Intel Tigerlake', + [ + DspMemorySegment( + 'imr', 0xb0000000, 16*1024*1024), + DspMemorySegment( + 'l2 hpsram', 0xbe000000, 46*64*1024), + DspMemorySegment( + 'l2 lpsram', 0xbe800000, 1*64*1024) + ]) + +DSP_MEM_SPACE_EXT = { + 'apl': APL_MEMORY_SPACE, + 'cnl': CNL_MEMORY_SPACE, + 'icl': ICL_MEMORY_SPACE, + 'tgl': TGL_MEMORY_SPACE +} + + +def main(args): + """ main function + """ + if sys.stdout.isatty(): + Attribute.no_colors = args.no_colors + else: + Attribute.no_colors = True + + Attribute.full_bytes = args.full_bytes + + fw_bin = parse_fw_bin(args.sof_ri_path, args.no_cse, args.verbose) + + if args.valid: + css_mft_hdr = fw_bin.get_comp('cse_mft').get_comp( + 'css_mft').get_comp('css_mft_hdr') + modulus = css_mft_hdr.adir['modulus'] + if 'Other' in modulus.val_type: + print('%s is not valid' % args.sof_ri_path) + sys.exit(2) + sys.exit(0) + + comp_filter = [] + if args.headers or args.no_modules: + comp_filter.append('Module Entry') + if args.no_headers: + comp_filter.append('CSE Manifest') + fw_bin.dump_info('', comp_filter) + if not args.no_memory: + mem = get_mem_map(args.sof_ri_path) + fw_bin.populate_mem_map(mem) + add_lmap_mem_info(args.sof_ri_path, mem) + print() + mem.dump_info() + + +if __name__ == "__main__": + ARGS = parse_params() + main(ARGS) diff --git a/units/audio/jobs.pxu b/units/audio/jobs.pxu index b9f4856..538d213 100644 --- a/units/audio/jobs.pxu +++ b/units/audio/jobs.pxu @@ -8,6 +8,22 @@ requires: command: cat /proc/asound/cards _description: Test to detect audio devices +plugin: shell +category_id: com.canonical.plainbox::audio +id: audio/valid-sof-firmware-sig +requires: + device.category == 'AUDIO' + package.name == 'linux-firmware' +command: + for fw in /lib/firmware/intel/sof/sof-*.ri; + do + # shellcheck disable=SC2016 + if xxd "${fw}" | grep -q '$CPD'; then + sof_ri_info.py --valid "${fw}" + fi + done +_description: Valid sof firmware signature + plugin: user-interact-verify category_id: com.canonical.plainbox::audio id: audio/playback_auto diff --git a/units/audio/test-plan.pxu b/units/audio/test-plan.pxu index f583b91..422b831 100644 --- a/units/audio/test-plan.pxu +++ b/units/audio/test-plan.pxu @@ -46,6 +46,7 @@ include: audio/alsa_info_collect audio/alsa_info_attachment audio/list_devices + audio/valid-sof-firmware-sig id: audio-cert-blockers unit: test plan |
