| # 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"] |