mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-04 04:27:34 +00:00
205 lines
8.8 KiB
Python
Executable file
205 lines
8.8 KiB
Python
Executable file
#! /usr/bin/env python3
|
|
import argparse
|
|
import logging
|
|
|
|
from pddbcommon import *
|
|
|
|
def main():
|
|
global DO_CI_TESTS
|
|
parser = argparse.ArgumentParser(description="Debug PDDB Images")
|
|
parser.add_argument(
|
|
"--name", required=False, help="pddb disk image root name", type=str, nargs='?', metavar=('name'), const='./pddb'
|
|
)
|
|
parser.add_argument(
|
|
"--loglevel", required=False, help="set logging level (INFO/DEBUG/WARNING/ERROR)", type=str, default="INFO",
|
|
)
|
|
parser.add_argument(
|
|
"--dump", required=False, help="Only dump the image, skip the automated CI checks", action="store_true"
|
|
)
|
|
parser.add_argument(
|
|
"--renode", required=False, help="Override flex-size settings and read a Renode bin file", action="store_true"
|
|
)
|
|
parser.add_argument(
|
|
"--smalldb", required=False, help="Override default size of PDDB and set it to 4MiB (for images built to that size only)", action="store_true"
|
|
)
|
|
parser.add_argument(
|
|
"--basis", type=str, help="Extra Bases to unlock, as `name:pass`. Each additional basis requires another --basis separator. Note that : is not legal to use in a Basis name.", action="append", nargs="+"
|
|
)
|
|
parser.add_argument(
|
|
"-p", "--pin", help="Unlock PIN", type=str, default='a'
|
|
)
|
|
parser.add_argument(
|
|
"--ci", help="Run in CI test mode. Requires all keys to have a specific checksum structure for automated checking.", action="store_true"
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
numeric_level = getattr(logging, args.loglevel.upper(), None)
|
|
if args.dump:
|
|
numeric_level = getattr(logging, 'DEBUG', None)
|
|
else:
|
|
numeric_level = getattr(logging, args.loglevel.upper(), None)
|
|
if not isinstance(numeric_level, int):
|
|
raise ValueError('Invalid log level: %s' % args.loglevel)
|
|
logging.basicConfig(level=numeric_level)
|
|
|
|
set_ci_tests_flag(args.ci)
|
|
|
|
if args.renode is True:
|
|
keyfile = "./emulation/renode-keybox.bin"
|
|
imagefile = "./tools/pddb-images/renode.bin"
|
|
basis_credentials = []
|
|
if args.basis:
|
|
for pair in args.basis:
|
|
credpair = pair[0].split(':', 1)
|
|
if len(credpair) != 2:
|
|
logging.error("Basis credential pair with name {} has a formatting problem, aborting!".format(credpair[0]))
|
|
exit(1)
|
|
basis_credentials += [credpair]
|
|
|
|
with open(keyfile, 'rb') as key_f:
|
|
keyrom = key_f.read()
|
|
with open(imagefile, 'rb') as img_f:
|
|
raw_img = img_f.read()
|
|
if args.smalldb:
|
|
raw_img = raw_img[0x01D80000:0x1D8_0000 + 1024 * 1024 * 4]
|
|
else:
|
|
raw_img = raw_img[0x01D80000:0x07F80000]
|
|
keys = extract_keys(keyrom, raw_img, args.pin, basis_credentials)
|
|
else:
|
|
if args.name == None:
|
|
keyfile = './tools/pddb-images/pddb.key'
|
|
imagefile = './tools/pddb-images/pddb.bin'
|
|
else:
|
|
keyfile = './tools/pddb-images/{}.key'.format(args.name)
|
|
imagefile = './tools/pddb-images/{}.bin'.format(args.name)
|
|
|
|
if args.dump:
|
|
DO_CI_TESTS = False
|
|
|
|
keys = {}
|
|
with open(keyfile, 'rb') as key_f:
|
|
raw_key = key_f.read()
|
|
num_keys = int.from_bytes(raw_key[:4], 'little')
|
|
for i in range(num_keys):
|
|
name_all = raw_key[4 + i*128 : 4 + i*128 + 64]
|
|
name_bytes = bytearray(b'')
|
|
for b in name_all:
|
|
if b != 0:
|
|
name_bytes.append(b)
|
|
else:
|
|
break
|
|
name = name_bytes.decode('utf8', errors='ignore')
|
|
key_data = raw_key[4 + i*128 + 64 : 4 + i*128 + 96]
|
|
key_pt = raw_key[4 + i*128 + 96 : 4 + i*128 + 128]
|
|
keys[name] = [key_pt, key_data]
|
|
|
|
logging.info("Found basis keys (pt, data):")
|
|
logging.info(str(keys))
|
|
|
|
# tunable parameters for a filesystem
|
|
global MBBB_PAGES
|
|
FSCB_PAGES = 16
|
|
FSCB_LEN_PAGES = 2
|
|
KEY_PAGES = 1
|
|
global PAGE_SIZE
|
|
global VPAGE_SIZE
|
|
MAX_DICTS = 16383
|
|
|
|
with open(imagefile, 'rb') as img_f:
|
|
raw_img = img_f.read()
|
|
if args.renode:
|
|
if args.smalldb:
|
|
raw_img = raw_img[0x01D80000:0x1D8_0000 + 1024 * 1024 * 4]
|
|
else:
|
|
raw_img = raw_img[0x01D80000:0x07F80000]
|
|
pddb_len = len(raw_img)
|
|
pddb_size_pages = pddb_len // PAGE_SIZE
|
|
logging.info("Disk size: 0x{:x}".format(pddb_len))
|
|
|
|
mbbb_offset = pddb_size_pages * Pte.PTE_LEN + PAGE_SIZE * KEY_PAGES
|
|
if mbbb_offset & (PAGE_SIZE - 1) != 0:
|
|
mbbb_offset = (mbbb_offset + PAGE_SIZE) & 0xFFFF_F000 # round up to nearest page
|
|
logging.info("MBBB: 0x{:x}".format(mbbb_offset))
|
|
|
|
img_index = 0
|
|
tables = decode_pagetable(raw_img, pddb_size_pages, keys, raw_img[mbbb_offset:mbbb_offset + MBBB_PAGES * PAGE_SIZE])
|
|
img_index += pddb_size_pages * Pte.PTE_LEN
|
|
if img_index & (PAGE_SIZE - 1) != 0:
|
|
img_index = (img_index + PAGE_SIZE) & 0xFFFF_F000
|
|
|
|
rawkeys = raw_img[img_index : img_index + PAGE_SIZE * KEY_PAGES]
|
|
logging.debug("Keys: 0x{:x}".format(img_index))
|
|
img_index += PAGE_SIZE * KEY_PAGES
|
|
|
|
mbbb = raw_img[img_index : img_index + PAGE_SIZE * MBBB_PAGES]
|
|
logging.debug("MBBB check: 0x{:x}".format(img_index))
|
|
img_index += PAGE_SIZE * MBBB_PAGES
|
|
|
|
fscb = decode_fscb(raw_img[img_index: img_index + PAGE_SIZE * FSCB_PAGES], keys, FSCB_LEN_PAGES=FSCB_LEN_PAGES)
|
|
logging.debug("FSCB: 0x{:x}".format(img_index))
|
|
img_index += PAGE_SIZE * FSCB_PAGES
|
|
|
|
logging.debug("Data: 0x{:x}".format(img_index))
|
|
data = raw_img[img_index:]
|
|
|
|
for name, key in keys.items():
|
|
if name in tables:
|
|
logging.info("Basis {}, key_pt: {}, key_data: {}".format(name, key[0].hex(), key[1].hex()))
|
|
v2p_table = tables[name][0]
|
|
p2v_table = tables[name][1]
|
|
# v2p_table[0xfe0fe0] = 0x1200* 0x100
|
|
|
|
basis_data = bytearray()
|
|
pp_start = v2p_table[VPAGE_SIZE]
|
|
# print("pp_start: {:x}".format(pp_start))
|
|
pp_data = data[pp_start:pp_start + PAGE_SIZE]
|
|
try:
|
|
pt_data = keycommit_decrypt(key[1], basis_aad(name), pp_data)
|
|
basis_data.extend(bytearray(pt_data))
|
|
logging.debug("decrypted vpage @ {:x} ppage @ {:x}".format(VPAGE_SIZE, v2p_table[VPAGE_SIZE]))
|
|
# print([hex(x) for x in basis_data[:256]])
|
|
basis = Basis(basis_data)
|
|
logging.info(basis.as_str())
|
|
|
|
basis_dicts = {}
|
|
dicts_found = 0
|
|
dict_index = 0
|
|
while dict_index < MAX_DICTS and dicts_found < basis.num_dicts:
|
|
bdict = BasisDicts(dict_index, v2p_table, data, key[1], name)
|
|
if bdict.valid:
|
|
basis_dicts[bdict.name] = bdict
|
|
dicts_found += 1
|
|
dict_index += 1
|
|
if dicts_found != basis.num_dicts:
|
|
logging.error("Expected {} dictionaries, only found {}; searched {}".format(basis.num_dicts, dicts_found, dict_index))
|
|
found_all_dicts = False
|
|
else:
|
|
found_all_dicts = True
|
|
|
|
logging.debug(" Dictionaries: ")
|
|
for bdict in basis_dicts.values():
|
|
logging.debug(bdict.as_str())
|
|
|
|
#d2 = basis_dicts["dict2"]
|
|
#logging.info("listing {} keys".format(len(d2.keys)))
|
|
#for key in d2.keys:
|
|
# logging.info("{}".format(key))
|
|
if args.ci == True:
|
|
logging.info("CI checks:")
|
|
for bdict in basis_dicts.values():
|
|
bdict.ci_check()
|
|
if found_all_dicts:
|
|
logging.info("All dicts were found.") # this message is searched for in CI, don't change it
|
|
else:
|
|
logging.error("Missing dictionaries, something is wrong.")
|
|
else:
|
|
for bdict in basis_dicts.values():
|
|
logging.info("==================================================================")
|
|
logging.info("Dict {}".format(bdict.as_str()))
|
|
|
|
except ValueError:
|
|
logging.error("couldn't decrypt basis root vpage @ {:x} ppage @ {:x}".format(VPAGE_SIZE, v2p_table[VPAGE_SIZE]))
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
exit(0)
|