blob: 8a1c0110e75de3fed827d4e7fe13e4fbdc84473f [file] [log] [blame]
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
CONST = struct(
ROM_EXT = 0x4552544f,
OWNER = 0x4f53544f,
TRUE = 0x739,
FALSE = 0x1d4,
)
_DEFAULT_USAGE = 0xa5a5a5a5
_SEL_DEVICE_ID = 1
_SEL_MANUF_STATE_CREATOR = (1 << 8)
_SEL_MANUF_STATE_OWNER = (1 << 9)
_SEL_LIFE_CYCLE_STATE = (1 << 10)
_HEXSTR = "0123456789abcdef"
def _hex(i):
# First "cast" i to a 32-bit unsigned int
i &= 0xFFFFFFFF
r = "0x"
r += _HEXSTR[(i >> 28) & 0xF]
r += _HEXSTR[(i >> 24) & 0xF]
r += _HEXSTR[(i >> 20) & 0xF]
r += _HEXSTR[(i >> 16) & 0xF]
r += _HEXSTR[(i >> 12) & 0xF]
r += _HEXSTR[(i >> 8) & 0xF]
r += _HEXSTR[(i >> 4) & 0xF]
r += _HEXSTR[(i >> 0) & 0xF]
return r
def _manifest_impl(ctx):
mf = {}
# All the easy parameters are simple assignments
if ctx.attr.signature:
mf["signature"] = _hex(ctx.attr.signature)
if ctx.attr.modulus:
mf["modulus"] = _hex(ctx.attr.modulus)
if ctx.attr.identifier:
mf["identifier"] = _hex(ctx.attr.identifier)
if ctx.attr.length:
mf["length"] = _hex(ctx.attr.length)
if ctx.attr.version_major:
mf["version_major"] = _hex(ctx.attr.version_major)
if ctx.attr.version_minor:
mf["version_minor"] = _hex(ctx.attr.version_minor)
if ctx.attr.security_version:
mf["security_version"] = _hex(ctx.attr.security_version)
if ctx.attr.timestamp:
mf["timestamp"] = _hex(ctx.attr.timestamp)
if ctx.attr.max_key_version:
mf["max_key_version"] = _hex(ctx.attr.max_key_version)
if ctx.attr.code_start:
mf["code_start"] = _hex(ctx.attr.code_start)
if ctx.attr.code_end:
mf["code_end"] = _hex(ctx.attr.code_end)
if ctx.attr.entry_point:
mf["entry_point"] = _hex(ctx.attr.entry_point)
# Address Translation is a bool, but encoded as an int so we can have
# a special value mean "unset" and so we can set to non-standard values
# for testing.
if ctx.attr.address_translation:
mf["address_translation"] = _hex(ctx.attr.address_translation)
# The binding_value, if provided, must be exactly 8 words.
if ctx.attr.binding_value:
if len(ctx.attr.binding_value) != 8:
fail("The binding_value must be exactly 8 words.")
mf["binding_value"] = _hex(ctx.attr.binding_value)
# The selector_bits are set based on the values of the usage_constraints.
uc = {}
selector_bits = 0
device_id = list(ctx.attr.device_id)
if len(device_id) > 8:
fail("The device_id must be 8 words or fewer.")
# Extend the device_id to 8 words, then set the selector_bits for each
# non-default word.
if len(device_id) < 8:
device_id.extend([_DEFAULT_USAGE] * (8 - len(device_id)))
for i, d in enumerate(device_id):
if d != _DEFAULT_USAGE:
selector_bits |= _SEL_DEVICE_ID << i
device_id[i] = _hex(d)
uc["device_id"] = device_id
# Set the selector bits for the remaining non-default values.
if ctx.attr.manuf_state_creator:
uc["manuf_state_creator"] = _hex(ctx.attr.manuf_state_creator)
selector_bits |= _SEL_MANUF_STATE_CREATOR
else:
uc["manuf_state_creator"] = _hex(_DEFAULT_USAGE)
if ctx.attr.manuf_state_owner:
uc["manuf_state_owner"] = _hex(ctx.attr.manuf_state_owner)
selector_bits |= _SEL_MANUF_STATE_OWNER
else:
uc["manuf_state_owner"] = _hex(_DEFAULT_USAGE)
if ctx.attr.life_cycle_state:
uc["life_cycle_state"] = _hex(ctx.attr.life_cycle_state)
selector_bits |= _SEL_LIFE_CYCLE_STATE
else:
uc["life_cycle_state"] = _hex(_DEFAULT_USAGE)
# If the user supplied selector_bits, check if they make sense.
if ctx.attr.selector_bits:
# If they don't match, fail unless explicitly permitted to set a
# bad value.
if ctx.attr.selector_bits != selector_bits and ctx.attr.selector_mismatch_is_failure:
fail("User provided selector_bits don't match computed selector_bits")
uc["selector_bits"] = _hex(ctx.attr.selector_bits)
else:
uc["selector_bits"] = _hex(selector_bits)
mf["usage_constraints"] = uc
file = ctx.actions.declare_file("{}.json".format(ctx.attr.name))
ctx.actions.write(file, json.encode_indent(mf))
return DefaultInfo(
files = depset([file]),
data_runfiles = ctx.runfiles(files = [file]),
)
manifest = rule(
implementation = _manifest_impl,
attrs = {
"signature": attr.string(doc = "Image signature as a hex-encoded string"),
"modulus": attr.string(doc = "Signing key modulus as a hex-encoded string"),
"selector_bits": attr.int(doc = "Usage constraint selector bits"),
"selector_mismatch_is_failure": attr.bool(default = True, doc = "A mismatch in computed selector bits is a failure"),
"device_id": attr.int_list(doc = "Usage constraint device ID"),
"manuf_state_creator": attr.int(doc = "Usage constraint for silicon creator manufacturing status"),
"manuf_state_owner": attr.int(doc = "Usage constraint for silicon owner manufacturing status"),
"life_cycle_state": attr.int(doc = "Usage constraint for life cycle status"),
"address_translation": attr.int(doc = "Whether this image uses address translation"),
"identifier": attr.int(doc = "Manifest identifier"),
"length": attr.int(doc = "Length of this image"),
"version_major": attr.int(doc = "Image major version"),
"version_minor": attr.int(doc = "Image minor version"),
"security_version": attr.int(doc = "Security version for anti-rollback protection"),
"timestamp": attr.int(doc = "Unix timestamp of the image"),
"binding_value": attr.int_list(doc = "Binding value used by key manager to derive secrets"),
"max_key_version": attr.int(doc = "Maximum allowed version for keys generated at the next boot stage"),
"code_start": attr.int(doc = "Start offset of the executable region in the image"),
"code_end": attr.int(doc = "End offset of the executable region in the image"),
"entry_point": attr.int(doc = "Offset of the first instruction in the image"),
},
)