def _validate_item(item): '''Validates an item within a partition''' item.setdefault("name", "unknown_name") item.setdefault("size", "0") item.setdefault("isdigest", "false") item.setdefault("ismubi", "false") # make sure these have the correct types item["isdigest"] = check_bool(item["isdigest"]) item["ismubi"] = check_bool(item["ismubi"]) item["size"] = check_int(item["size"]) item_width = item["size"] * 8 # defaults are handled differently in case of mubi if item["ismubi"]: if not is_width_valid(item_width): raise RuntimeError("Mubi value {} has invalid width".format( item["name"])) # Convert default to correct mubi value item.setdefault("inv_default", "false") item["inv_default"] = check_bool(item["inv_default"]) item["inv_default"] = mubi_value_as_int(item["inv_default"], item_width) else: # Generate random constant to be used when partition has # not been initialized yet or when it is in error state. random_or_hexvalue(item, "inv_default", item_width)
def create_mmap_table(self): header = [ "Index", "Partition", "Size [B]", "Access Granule", "Item", "Byte Address", "Size [B]" ] table = [header] colalign = ("center", ) * len(header) for k, part in enumerate(self.config["partitions"]): for j, item in enumerate(part["items"]): granule = "64bit" if check_bool(part["secret"]) else "32bit" if check_bool(item["isdigest"]): granule = "64bit" name = "[{}](#Reg_{}_0)".format(item["name"], item["name"].lower()) else: name = item["name"] if j == 0: row = [str(k), part["name"], str(part["size"]), granule] else: row = ["", "", "", granule] row.extend([ name, "0x{:03X}".format(check_int(item["offset"])), str(item["size"]) ]) table.append(row) return tabulate(table, headers="firstrow", tablefmt="pipe", colalign=colalign)
def create_partitions_table(self): header = [ "Partition", "Secret", "Buffered", "WR Lockable", "RD Lockable", "Description" ] table = [header] colalign = ("center", ) * len(header) for part in self.config["partitions"]: is_secret = "yes" if check_bool(part["secret"]) else "no" is_buffered = "yes" if part["variant"] in [ "Buffered", "LifeCycle" ] else "no" wr_lockable = "no" if part["write_lock"].lower() in ["csr", "digest"]: wr_lockable = "yes (" + part["write_lock"] + ")" rd_lockable = "no" if part["read_lock"].lower() in ["csr", "digest"]: rd_lockable = "yes (" + part["read_lock"] + ")" # remove newlines desc = ' '.join(part["desc"].split()) row = [ part["name"], is_secret, is_buffered, wr_lockable, rd_lockable, desc ] table.append(row) return tabulate(table, headers="firstrow", tablefmt="pipe", colalign=colalign)
def create_digests_table(self): header = ["Digest Name", " Affected Partition", "Calculated by HW"] table = [header] colalign = ("center", ) * len(header) for part in self.config["partitions"]: if check_bool(part["hw_digest"]) or check_bool(part["sw_digest"]): is_hw_digest = "yes" if check_bool(part["hw_digest"]) else "no" for item in part["items"]: if check_bool(item["isdigest"]): name = "[{}](#Reg_{}_0)".format( item["name"], item["name"].lower()) row = [name, part["name"], is_hw_digest] table.append(row) break else: raise RuntimeError( "Partition with digest does not contain a digest item") return tabulate(table, headers="firstrow", tablefmt="pipe", colalign=colalign)
def merge_item_data(self, part, item): '''This validates and merges the item data into the memory map dict''' item.setdefault('name', 'unknown_name') mmap_item = self.get_item(part['name'], item['name']) if mmap_item is None: raise RuntimeError('Item {} does not exist'.format(item['name'])) item_size = mmap_item['size'] item_width = item_size * 8 # if needed, resolve the mubi value first if mmap_item['ismubi']: mubi_str = "mubi " mubi_val_str = " kMultiBitBool{}".format(item_width) item.setdefault("value", "false") item["value"] = check_bool(item["value"]) mubi_val_str += "True" if item["value"] else "False" item["value"] = mubi_value_as_int(item["value"], item_width) else: mubi_str = "" mubi_val_str = "" item.setdefault('value', '0x0') random_or_hexvalue(item, 'value', item_width) mmap_item['value'] = item['value'] log.info('> Adding {}item {} with size {}B and value{}:'.format( mubi_str, item['name'], item_size, mubi_val_str)) fmt_str = '{:0' + str(item_size * 2) + 'x}' value_str = fmt_str.format(item['value']) bytes_per_line = 8 j = 0 while value_str: # Print out max 64bit per line line_str = '' for k in range(bytes_per_line): num_chars = min(len(value_str), 2) line_str += value_str[-num_chars:] if k < bytes_per_line - 1: line_str += ' ' value_str = value_str[:len(value_str) - num_chars] log.info(' {:06x}: '.format(j) + line_str) j += bytes_per_line # Key accounting item_check = item.copy() del item_check['name'] del item_check['value'] _check_unused_keys(item_check, 'in item {}'.format(item['name']))
def _validate_part(part, offset, key_names): '''Validates a partition within the OTP memory map''' part.setdefault("offset", offset) part.setdefault("name", "unknown_name") part.setdefault("variant", "Unbuffered") part.setdefault("size", "0") part.setdefault("secret", "false") part.setdefault("sw_digest", "false") part.setdefault("hw_digest", "false") part.setdefault("write_lock", "none") part.setdefault("read_lock", "none") part.setdefault("key_sel", "NoKey") log.info("Partition {} at offset {} with size {}".format( part["name"], part["offset"], part["size"])) # Make sure these are boolean types (simplifies the mako templates) part["secret"] = check_bool(part["secret"]) part["sw_digest"] = check_bool(part["sw_digest"]) part["hw_digest"] = check_bool(part["hw_digest"]) part["bkout_type"] = check_bool(part["bkout_type"]) # Make sure this has integer type. part["size"] = check_int(part["size"]) # basic checks if part["variant"] not in ["Unbuffered", "Buffered", "LifeCycle"]: log.error("Invalid partition type {}".format(part["variant"])) exit(1) if part["key_sel"] not in (["NoKey"] + key_names): log.error("Invalid key sel {}".format(part["key_sel"])) exit(1) if check_bool(part["secret"]) and part["key_sel"] == "NoKey": log.error( "A secret partition needs a key select value other than NoKey") exit(1) if part["write_lock"].lower() not in ["digest", "csr", "none"]: log.error("Invalid value for write_lock") exit(1) if part["read_lock"].lower() not in ["digest", "csr", "none"]: log.error("Invalid value for read_lock") exit(1) if part["sw_digest"] and part["hw_digest"]: log.error( "Partition cannot support both a SW and a HW digest at the same time." ) exit(1) if part["variant"] == "Unbuffered" and not part["sw_digest"]: log.error( "Unbuffered partitions without digest are not supported at the moment." ) exit(1) if not part["sw_digest"] and not part["hw_digest"]: if part["write_lock"].lower() == "digest" or part["read_lock"].lower( ) == "digest": log.error( "A partition can only be write/read lockable if it has a hw or sw digest." ) exit(1) if check_int(part["offset"]) % 8: log.error("Partition offset must be 64bit aligned") exit(1) if check_int(part["size"]) % 8: log.error("Partition size must be 64bit aligned") exit(1) if len(part["items"]) == 0: log.warning("Partition does not contain any items.")
def _validate_part(part, key_names): '''Validates a partition within the OTP memory map''' part.setdefault("name", "unknown_name") part.setdefault("variant", "Unbuffered") part.setdefault("secret", False) part.setdefault("sw_digest", False) part.setdefault("hw_digest", False) part.setdefault("write_lock", "none") part.setdefault("read_lock", "none") part.setdefault("key_sel", "NoKey") part.setdefault("absorb", False) log.info("Validating partition {}".format(part["name"])) # Make sure these are boolean types (simplifies the mako templates) part["secret"] = check_bool(part["secret"]) part["sw_digest"] = check_bool(part["sw_digest"]) part["hw_digest"] = check_bool(part["hw_digest"]) part["bkout_type"] = check_bool(part["bkout_type"]) part["ecc_fatal"] = check_bool(part["ecc_fatal"]) # basic checks if part["variant"] not in ["Unbuffered", "Buffered", "LifeCycle"]: raise RuntimeError("Invalid partition type {}".format(part["variant"])) if part["key_sel"] not in (["NoKey"] + key_names): raise RuntimeError("Invalid key sel {}".format(part["key_sel"])) if check_bool(part["secret"]) and part["key_sel"] == "NoKey": raise RuntimeError( "A secret partition needs a key select value other than NoKey") if part["write_lock"].lower() not in ["digest", "csr", "none"]: raise RuntimeError("Invalid value for write_lock") if part["read_lock"].lower() not in ["digest", "csr", "none"]: raise RuntimeError("Invalid value for read_lock") if part["sw_digest"] and part["hw_digest"]: raise RuntimeError( "Partition cannot support both a SW and a HW digest at the same time." ) if part["variant"] == "Unbuffered" and not part["sw_digest"]: raise RuntimeError( "Unbuffered partitions without digest are not supported at the moment." ) if not part["sw_digest"] and not part["hw_digest"]: if part["write_lock"].lower() == "digest" or part["read_lock"].lower( ) == "digest": raise RuntimeError( "A partition can only be write/read lockable if it has a hw or sw digest." ) if not isinstance(part['items'], list): raise RuntimeError('the "items" key must contain a list') if len(part["items"]) == 0: log.warning("Partition does not contain any items.") # validate items and calculate partition size if necessary size = 0 for item in part["items"]: _validate_item(item) size += item["size"] # if size not previously defined, set it if "size" not in part: part["size"] = _calc_size(part, size) # Make sure this has integer type. part["size"] = check_int(part["size"]) # Make sure partition size is aligned. if part["size"] % SCRAMBLE_BLOCK_WIDTH: raise RuntimeError("Partition size must be 64bit aligned")
def merge_part_data(self, part): '''This validates and merges the partition data into the memory map dict''' part.setdefault('items', []) if not isinstance(part['items'], list): raise RuntimeError('the "items" key must contain a list') # Check if partition name exists in memory map part.setdefault('name', 'unknown_name') mmap_part = self.get_part(part['name']) if mmap_part is None: raise RuntimeError('Partition {} does not exist'.format( part['name'])) # Only partitions with a hardware digest can be locked. part.setdefault('lock', 'false') part['lock'] = check_bool(part['lock']) if part['lock'] and not \ mmap_part['hw_digest']: raise RuntimeError( 'Partition {} does not contain a hardware digest'.format( part['name'])) # Augment memory map datastructure with lock bit. mmap_part['lock'] = part['lock'] if part['name'] == 'LIFE_CYCLE': part.setdefault('state', 'RAW') part.setdefault('count', 0) part['count'] = check_int(part['count']) if len(part['items']) > 0: raise RuntimeError( 'Life cycle items cannot directly be overridden') if part['lock']: raise RuntimeError('Life cycle partition cannot be locked') if part['count'] == 0 and part['state'] != "RAW": raise RuntimeError( 'Life cycle transition counter can only be zero in the RAW state' ) # Augment life cycle partition with correct life cycle encoding state = self.lc_state.encode('lc_state', str(part['state'])) count = self.lc_state.encode('lc_cnt', str(part['count'])) part['items'] = [{ 'name': 'LC_STATE', 'value': '0x{:X}'.format(state) }, { 'name': 'LC_TRANSITION_CNT', 'value': '0x{:X}'.format(count) }] # Key accounting part_check = part.copy() del part_check['state'] del part_check['count'] else: # Key accounting part_check = part.copy() if len(part['items']) == 0: log.warning("Partition does not contain any items.") # Key accounting del part_check['items'] del part_check['name'] del part_check['lock'] _check_unused_keys(part_check, "in partition {}".format(part['name']))