Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 1 | # Copyright lowRISC contributors. |
| 2 | # Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| 3 | # SPDX-License-Identifier: Apache-2.0 |
| 4 | |
Alphan Ulusoy | 59a4cd4 | 2022-11-01 15:23:56 -0400 | [diff] [blame] | 5 | load("//rules:const.bzl", "CONST", "hex") |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 6 | |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 7 | _SEL_DEVICE_ID = 1 |
| 8 | _SEL_MANUF_STATE_CREATOR = (1 << 8) |
| 9 | _SEL_MANUF_STATE_OWNER = (1 << 9) |
| 10 | _SEL_LIFE_CYCLE_STATE = (1 << 10) |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 11 | |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 12 | def _manifest_impl(ctx): |
| 13 | mf = {} |
| 14 | |
| 15 | # All the easy parameters are simple assignments |
| 16 | if ctx.attr.signature: |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 17 | mf["signature"] = ctx.attr.signature |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 18 | if ctx.attr.modulus: |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 19 | mf["modulus"] = ctx.attr.modulus |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 20 | if ctx.attr.identifier: |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 21 | mf["identifier"] = ctx.attr.identifier |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 22 | if ctx.attr.length: |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 23 | mf["length"] = ctx.attr.length |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 24 | if ctx.attr.version_major: |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 25 | mf["version_major"] = ctx.attr.version_major |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 26 | if ctx.attr.version_minor: |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 27 | mf["version_minor"] = ctx.attr.version_minor |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 28 | if ctx.attr.security_version: |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 29 | mf["security_version"] = ctx.attr.security_version |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 30 | if ctx.attr.timestamp: |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 31 | mf["timestamp"] = ctx.attr.timestamp |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 32 | if ctx.attr.max_key_version: |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 33 | mf["max_key_version"] = ctx.attr.max_key_version |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 34 | if ctx.attr.code_start: |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 35 | mf["code_start"] = ctx.attr.code_start |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 36 | if ctx.attr.code_end: |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 37 | mf["code_end"] = ctx.attr.code_end |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 38 | if ctx.attr.entry_point: |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 39 | mf["entry_point"] = ctx.attr.entry_point |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 40 | |
| 41 | # Address Translation is a bool, but encoded as an int so we can have |
| 42 | # a special value mean "unset" and so we can set to non-standard values |
| 43 | # for testing. |
| 44 | if ctx.attr.address_translation: |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 45 | mf["address_translation"] = ctx.attr.address_translation |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 46 | |
| 47 | # The binding_value, if provided, must be exactly 8 words. |
| 48 | if ctx.attr.binding_value: |
| 49 | if len(ctx.attr.binding_value) != 8: |
| 50 | fail("The binding_value must be exactly 8 words.") |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 51 | mf["binding_value"] = [v for v in ctx.attr.binding_value] |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 52 | |
| 53 | # The selector_bits are set based on the values of the usage_constraints. |
| 54 | uc = {} |
| 55 | selector_bits = 0 |
| 56 | device_id = list(ctx.attr.device_id) |
| 57 | if len(device_id) > 8: |
| 58 | fail("The device_id must be 8 words or fewer.") |
| 59 | |
| 60 | # Extend the device_id to 8 words, then set the selector_bits for each |
| 61 | # non-default word. |
| 62 | if len(device_id) < 8: |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 63 | device_id.extend([hex(CONST.DEFAULT_USAGE_CONSTRAINTS)] * (8 - len(device_id))) |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 64 | for i, d in enumerate(device_id): |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 65 | if d != hex(CONST.DEFAULT_USAGE_CONSTRAINTS): |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 66 | selector_bits |= _SEL_DEVICE_ID << i |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 67 | device_id[i] = d |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 68 | uc["device_id"] = device_id |
| 69 | |
| 70 | # Set the selector bits for the remaining non-default values. |
| 71 | if ctx.attr.manuf_state_creator: |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 72 | uc["manuf_state_creator"] = ctx.attr.manuf_state_creator |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 73 | selector_bits |= _SEL_MANUF_STATE_CREATOR |
| 74 | else: |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 75 | uc["manuf_state_creator"] = hex(CONST.DEFAULT_USAGE_CONSTRAINTS) |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 76 | |
| 77 | if ctx.attr.manuf_state_owner: |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 78 | uc["manuf_state_owner"] = ctx.attr.manuf_state_owner |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 79 | selector_bits |= _SEL_MANUF_STATE_OWNER |
| 80 | else: |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 81 | uc["manuf_state_owner"] = hex(CONST.DEFAULT_USAGE_CONSTRAINTS) |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 82 | |
| 83 | if ctx.attr.life_cycle_state: |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 84 | uc["life_cycle_state"] = ctx.attr.life_cycle_state |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 85 | selector_bits |= _SEL_LIFE_CYCLE_STATE |
| 86 | else: |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 87 | uc["life_cycle_state"] = hex(CONST.DEFAULT_USAGE_CONSTRAINTS) |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 88 | |
| 89 | # If the user supplied selector_bits, check if they make sense. |
| 90 | if ctx.attr.selector_bits: |
| 91 | # If they don't match, fail unless explicitly permitted to set a |
| 92 | # bad value. |
Miles Dai | 620fda8 | 2022-11-04 16:56:36 -0400 | [diff] [blame] | 93 | if int(ctx.attr.selector_bits, base = 16) != selector_bits and ctx.attr.selector_mismatch_is_failure: |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 94 | fail("User provided selector_bits ({}) don't match computed selector_bits ({})".format(ctx.attr.selector_bits, selector_bits)) |
| 95 | uc["selector_bits"] = ctx.attr.selector_bits |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 96 | else: |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 97 | uc["selector_bits"] = selector_bits |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 98 | |
| 99 | mf["usage_constraints"] = uc |
| 100 | |
| 101 | file = ctx.actions.declare_file("{}.json".format(ctx.attr.name)) |
| 102 | ctx.actions.write(file, json.encode_indent(mf)) |
| 103 | return DefaultInfo( |
| 104 | files = depset([file]), |
| 105 | data_runfiles = ctx.runfiles(files = [file]), |
| 106 | ) |
| 107 | |
Alphan Ulusoy | bff55d4 | 2022-10-14 12:00:11 -0400 | [diff] [blame] | 108 | _manifest = rule( |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 109 | implementation = _manifest_impl, |
Miles Dai | 620fda8 | 2022-11-04 16:56:36 -0400 | [diff] [blame] | 110 | # Manifest attrs are supplied as strings due to Bazel limiting int types to 32-bit signed integers |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 111 | attrs = { |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 112 | "signature": attr.string(doc = "Image signature as a 0x-prefixed hex-encoded string"), |
| 113 | "modulus": attr.string(doc = "Signing key modulus as a 0x-prefixed hex-encoded string"), |
| 114 | "selector_bits": attr.string(doc = "Usage constraint selector bits as a 0x-prefixed hex-encoded string"), |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 115 | "selector_mismatch_is_failure": attr.bool(default = True, doc = "A mismatch in computed selector bits is a failure"), |
Miles Dai | 38700d5 | 2023-01-11 15:47:40 -0500 | [diff] [blame] | 116 | "device_id": attr.string_list(doc = "Usage constraint device ID as a 0x-prefixed hex-encoded string"), |
| 117 | "manuf_state_creator": attr.string(doc = "Usage constraint for silicon creator manufacturing status as a 0x-prefixed hex-encoded string"), |
| 118 | "manuf_state_owner": attr.string(doc = "Usage constraint for silicon owner manufacturing status as a 0x-prefixed hex-encoded string"), |
| 119 | "life_cycle_state": attr.string(doc = "Usage constraint for life cycle status as a 0x-prefixed hex-encoded string"), |
| 120 | "address_translation": attr.string(doc = "Whether this image uses address translation as a 0x-prefixed hex-encoded string"), |
| 121 | "identifier": attr.string(doc = "Manifest identifier as a 0x-prefixed hex-encoded string"), |
| 122 | "length": attr.string(doc = "Length of this image as a 0x-prefixed hex-encoded string"), |
| 123 | "version_major": attr.string(doc = "Image major version as a 0x-prefixed hex-encoded string"), |
| 124 | "version_minor": attr.string(doc = "Image minor version as a 0x-prefixed hex-encoded string"), |
| 125 | "security_version": attr.string(doc = "Security version for anti-rollback protection as a 0x-prefixed hex-encoded string"), |
| 126 | "timestamp": attr.string(doc = "Unix timestamp of the image as a 0x-prefixed hex-encoded string"), |
| 127 | "binding_value": attr.string_list(doc = "Binding value used by key manager to derive secrets as a 0x-prefixed hex-encoded string"), |
| 128 | "max_key_version": attr.string(doc = "Maximum allowed version for keys generated at the next boot stage as a 0x-prefixed hex-encoded string"), |
| 129 | "code_start": attr.string(doc = "Start offset of the executable region in the image as a 0x-prefixed hex-encoded string"), |
| 130 | "code_end": attr.string(doc = "End offset of the executable region in the image as a 0x-prefixed hex-encoded string"), |
| 131 | "entry_point": attr.string(doc = "Offset of the first instruction in the image as a 0x-prefixed hex-encoded string"), |
Chris Frantz | 0f706ea | 2022-06-16 15:04:55 -0700 | [diff] [blame] | 132 | }, |
| 133 | ) |
Alphan Ulusoy | bff55d4 | 2022-10-14 12:00:11 -0400 | [diff] [blame] | 134 | |
| 135 | def manifest(d): |
| 136 | _manifest(**d) |
| 137 | return d["name"] |