1*8617a60dSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*8617a60dSAndroid Build Coastguard Worker# Copyright 2024 The ChromiumOS Authors 3*8617a60dSAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*8617a60dSAndroid Build Coastguard Worker# found in the LICENSE file. 5*8617a60dSAndroid Build Coastguard Worker 6*8617a60dSAndroid Build Coastguard Worker"""Utility for vboot nvdata (nvram, nvstorage).""" 7*8617a60dSAndroid Build Coastguard Worker 8*8617a60dSAndroid Build Coastguard Workerimport argparse 9*8617a60dSAndroid Build Coastguard Worker 10*8617a60dSAndroid Build Coastguard Worker 11*8617a60dSAndroid Build Coastguard WorkerNVDATA_SIZE = 16 12*8617a60dSAndroid Build Coastguard Worker 13*8617a60dSAndroid Build Coastguard Worker 14*8617a60dSAndroid Build Coastguard Workerdef get_crc8(data, size): 15*8617a60dSAndroid Build Coastguard Worker """Calculate CRC-8.""" 16*8617a60dSAndroid Build Coastguard Worker # CRC-8 ITU version, with x^8 + x^2 + x + 1 polynomial. 17*8617a60dSAndroid Build Coastguard Worker # Note that result will evaluate to zero for a buffer of all zeroes. 18*8617a60dSAndroid Build Coastguard Worker crc = 0 19*8617a60dSAndroid Build Coastguard Worker 20*8617a60dSAndroid Build Coastguard Worker # Calculate CRC-8 directly. A table-based algorithm would be faster, 21*8617a60dSAndroid Build Coastguard Worker # but for only a few bytes it isn't worth the code size. 22*8617a60dSAndroid Build Coastguard Worker for i in range(size): 23*8617a60dSAndroid Build Coastguard Worker crc ^= data[i] << 8 24*8617a60dSAndroid Build Coastguard Worker for _ in range(8): 25*8617a60dSAndroid Build Coastguard Worker if crc & 0x8000: 26*8617a60dSAndroid Build Coastguard Worker crc ^= 0x1070 << 3 27*8617a60dSAndroid Build Coastguard Worker crc = (crc << 1) & 0xFFFFFFFF 28*8617a60dSAndroid Build Coastguard Worker 29*8617a60dSAndroid Build Coastguard Worker return (crc >> 8) % 256 30*8617a60dSAndroid Build Coastguard Worker 31*8617a60dSAndroid Build Coastguard Worker 32*8617a60dSAndroid Build Coastguard Workerdef verify_crc8(entry): 33*8617a60dSAndroid Build Coastguard Worker """Verify CRC-8 of `entry`.""" 34*8617a60dSAndroid Build Coastguard Worker assert len(entry) == NVDATA_SIZE 35*8617a60dSAndroid Build Coastguard Worker expected_crc8 = get_crc8(entry, NVDATA_SIZE - 1) 36*8617a60dSAndroid Build Coastguard Worker crc8 = entry[NVDATA_SIZE - 1] 37*8617a60dSAndroid Build Coastguard Worker return crc8 == expected_crc8 38*8617a60dSAndroid Build Coastguard Worker 39*8617a60dSAndroid Build Coastguard Worker 40*8617a60dSAndroid Build Coastguard Workerdef process_entry(entry, offset): 41*8617a60dSAndroid Build Coastguard Worker """Process an nvdata entry.""" 42*8617a60dSAndroid Build Coastguard Worker data = " ".join(f"{x:02x}" for x in entry) 43*8617a60dSAndroid Build Coastguard Worker if all(x == 0xFF for x in entry): 44*8617a60dSAndroid Build Coastguard Worker result = "EMPTY" 45*8617a60dSAndroid Build Coastguard Worker else: 46*8617a60dSAndroid Build Coastguard Worker is_valid = verify_crc8(entry) 47*8617a60dSAndroid Build Coastguard Worker result = "VALID" if is_valid else "CRC ERROR" 48*8617a60dSAndroid Build Coastguard Worker print(f"{offset:08x} {data} {result}") 49*8617a60dSAndroid Build Coastguard Worker 50*8617a60dSAndroid Build Coastguard Worker 51*8617a60dSAndroid Build Coastguard Workerdef dump(nvdata_file): 52*8617a60dSAndroid Build Coastguard Worker """Show the content of `nvdata_file`.""" 53*8617a60dSAndroid Build Coastguard Worker with open(nvdata_file, "rb") as f: 54*8617a60dSAndroid Build Coastguard Worker nvdata = f.read() 55*8617a60dSAndroid Build Coastguard Worker assert len(nvdata) % NVDATA_SIZE == 0 56*8617a60dSAndroid Build Coastguard Worker for i in range(len(nvdata) // NVDATA_SIZE): 57*8617a60dSAndroid Build Coastguard Worker offset = i * NVDATA_SIZE 58*8617a60dSAndroid Build Coastguard Worker entry = nvdata[offset : offset + NVDATA_SIZE] 59*8617a60dSAndroid Build Coastguard Worker process_entry(entry, offset) 60*8617a60dSAndroid Build Coastguard Worker 61*8617a60dSAndroid Build Coastguard Worker 62*8617a60dSAndroid Build Coastguard Workerdef verify_hex_entry(hex_string): 63*8617a60dSAndroid Build Coastguard Worker """Verify an nvdata entry.""" 64*8617a60dSAndroid Build Coastguard Worker values = [] 65*8617a60dSAndroid Build Coastguard Worker for s in hex_string.split(): 66*8617a60dSAndroid Build Coastguard Worker s = s.removeprefix("0x") 67*8617a60dSAndroid Build Coastguard Worker for i in range(0, len(s), 2): 68*8617a60dSAndroid Build Coastguard Worker value = int(s[i : i + 2], 16) 69*8617a60dSAndroid Build Coastguard Worker values.append(value) 70*8617a60dSAndroid Build Coastguard Worker if len(values) != NVDATA_SIZE: 71*8617a60dSAndroid Build Coastguard Worker raise ValueError( 72*8617a60dSAndroid Build Coastguard Worker f"Hex string should contain {NVDATA_SIZE} bytes" 73*8617a60dSAndroid Build Coastguard Worker f", {len(values)} found" 74*8617a60dSAndroid Build Coastguard Worker ) 75*8617a60dSAndroid Build Coastguard Worker 76*8617a60dSAndroid Build Coastguard Worker entry = bytes(values) 77*8617a60dSAndroid Build Coastguard Worker is_valid = verify_crc8(entry) 78*8617a60dSAndroid Build Coastguard Worker print("VALID" if is_valid else "INVALID") 79*8617a60dSAndroid Build Coastguard Worker 80*8617a60dSAndroid Build Coastguard Worker 81*8617a60dSAndroid Build Coastguard Workerdef main(): 82*8617a60dSAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 83*8617a60dSAndroid Build Coastguard Worker group = parser.add_mutually_exclusive_group() 84*8617a60dSAndroid Build Coastguard Worker group.add_argument("-f", "--file", help="RW_NVRAM file to dump") 85*8617a60dSAndroid Build Coastguard Worker group.add_argument( 86*8617a60dSAndroid Build Coastguard Worker "--hex", 87*8617a60dSAndroid Build Coastguard Worker help=( 88*8617a60dSAndroid Build Coastguard Worker f"Hex string of {NVDATA_SIZE} bytes to verify (for example" 89*8617a60dSAndroid Build Coastguard Worker " '50 40 00 00 00 02 00 02 00 fe ff 00 00 ff ff 60')" 90*8617a60dSAndroid Build Coastguard Worker ), 91*8617a60dSAndroid Build Coastguard Worker ) 92*8617a60dSAndroid Build Coastguard Worker 93*8617a60dSAndroid Build Coastguard Worker args = parser.parse_args() 94*8617a60dSAndroid Build Coastguard Worker if args.file: 95*8617a60dSAndroid Build Coastguard Worker dump(args.file) 96*8617a60dSAndroid Build Coastguard Worker elif args.hex: 97*8617a60dSAndroid Build Coastguard Worker verify_hex_entry(args.hex) 98*8617a60dSAndroid Build Coastguard Worker else: 99*8617a60dSAndroid Build Coastguard Worker parser.print_help() 100*8617a60dSAndroid Build Coastguard Worker 101*8617a60dSAndroid Build Coastguard Worker 102*8617a60dSAndroid Build Coastguard Workerif __name__ == "__main__": 103*8617a60dSAndroid Build Coastguard Worker main() 104