blob: e359dbf9d62996c95c105335ce19ee7be8d229c2 [file] [log] [blame]
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
load("//rules:const.bzl", "CONST", "hex")
_SEL_DEVICE_ID = 1
_SEL_MANUF_STATE_CREATOR = (1 << 8)
_SEL_MANUF_STATE_OWNER = (1 << 9)
_SEL_LIFE_CYCLE_STATE = (1 << 10)
def _manifest_impl(ctx):
mf = {}
# All the easy parameters are simple assignments
if ctx.attr.signature:
mf["signature"] = ctx.attr.signature
if ctx.attr.modulus:
mf["modulus"] = ctx.attr.modulus
if ctx.attr.identifier:
mf["identifier"] = ctx.attr.identifier
if ctx.attr.length:
mf["length"] = ctx.attr.length
if ctx.attr.version_major:
mf["version_major"] = ctx.attr.version_major
if ctx.attr.version_minor:
mf["version_minor"] = ctx.attr.version_minor
if ctx.attr.security_version:
mf["security_version"] = ctx.attr.security_version
if ctx.attr.timestamp:
mf["timestamp"] = ctx.attr.timestamp
if ctx.attr.max_key_version:
mf["max_key_version"] = ctx.attr.max_key_version
if ctx.attr.code_start:
mf["code_start"] = ctx.attr.code_start
if ctx.attr.code_end:
mf["code_end"] = ctx.attr.code_end
if ctx.attr.entry_point:
mf["entry_point"] = 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"] = 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"] = [v for v in 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([hex(CONST.DEFAULT_USAGE_CONSTRAINTS)] * (8 - len(device_id)))
for i, d in enumerate(device_id):
if d != hex(CONST.DEFAULT_USAGE_CONSTRAINTS):
selector_bits |= _SEL_DEVICE_ID << i
device_id[i] = 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"] = ctx.attr.manuf_state_creator
selector_bits |= _SEL_MANUF_STATE_CREATOR
else:
uc["manuf_state_creator"] = hex(CONST.DEFAULT_USAGE_CONSTRAINTS)
if ctx.attr.manuf_state_owner:
uc["manuf_state_owner"] = ctx.attr.manuf_state_owner
selector_bits |= _SEL_MANUF_STATE_OWNER
else:
uc["manuf_state_owner"] = hex(CONST.DEFAULT_USAGE_CONSTRAINTS)
if ctx.attr.life_cycle_state:
uc["life_cycle_state"] = ctx.attr.life_cycle_state
selector_bits |= _SEL_LIFE_CYCLE_STATE
else:
uc["life_cycle_state"] = hex(CONST.DEFAULT_USAGE_CONSTRAINTS)
# 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 int(ctx.attr.selector_bits, base = 16) != selector_bits and ctx.attr.selector_mismatch_is_failure:
fail("User provided selector_bits ({}) don't match computed selector_bits ({})".format(ctx.attr.selector_bits, selector_bits))
uc["selector_bits"] = ctx.attr.selector_bits
else:
uc["selector_bits"] = 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,
# Manifest attrs are supplied as strings due to Bazel limiting int types to 32-bit signed integers
attrs = {
"signature": attr.string(doc = "Image signature as a 0x-prefixed hex-encoded string"),
"modulus": attr.string(doc = "Signing key modulus as a 0x-prefixed hex-encoded string"),
"selector_bits": attr.string(doc = "Usage constraint selector bits as a 0x-prefixed hex-encoded string"),
"selector_mismatch_is_failure": attr.bool(default = True, doc = "A mismatch in computed selector bits is a failure"),
"device_id": attr.string_list(doc = "Usage constraint device ID as a 0x-prefixed hex-encoded string"),
"manuf_state_creator": attr.string(doc = "Usage constraint for silicon creator manufacturing status as a 0x-prefixed hex-encoded string"),
"manuf_state_owner": attr.string(doc = "Usage constraint for silicon owner manufacturing status as a 0x-prefixed hex-encoded string"),
"life_cycle_state": attr.string(doc = "Usage constraint for life cycle status as a 0x-prefixed hex-encoded string"),
"address_translation": attr.string(doc = "Whether this image uses address translation as a 0x-prefixed hex-encoded string"),
"identifier": attr.string(doc = "Manifest identifier as a 0x-prefixed hex-encoded string"),
"length": attr.string(doc = "Length of this image as a 0x-prefixed hex-encoded string"),
"version_major": attr.string(doc = "Image major version as a 0x-prefixed hex-encoded string"),
"version_minor": attr.string(doc = "Image minor version as a 0x-prefixed hex-encoded string"),
"security_version": attr.string(doc = "Security version for anti-rollback protection as a 0x-prefixed hex-encoded string"),
"timestamp": attr.string(doc = "Unix timestamp of the image as a 0x-prefixed hex-encoded string"),
"binding_value": attr.string_list(doc = "Binding value used by key manager to derive secrets as a 0x-prefixed hex-encoded string"),
"max_key_version": attr.string(doc = "Maximum allowed version for keys generated at the next boot stage as a 0x-prefixed hex-encoded string"),
"code_start": attr.string(doc = "Start offset of the executable region in the image as a 0x-prefixed hex-encoded string"),
"code_end": attr.string(doc = "End offset of the executable region in the image as a 0x-prefixed hex-encoded string"),
"entry_point": attr.string(doc = "Offset of the first instruction in the image as a 0x-prefixed hex-encoded string"),
},
)
def manifest(d):
_manifest(**d)
return d["name"]