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