|  | # Copyright lowRISC contributors. | 
|  | # Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | # SPDX-License-Identifier: Apache-2.0 | 
|  |  | 
|  | load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain") | 
|  | load( | 
|  | "//rules:cc_side_outputs.bzl", | 
|  | "rv_asm", | 
|  | "rv_llvm_ir", | 
|  | "rv_preprocess", | 
|  | "rv_relink_with_linkmap", | 
|  | ) | 
|  | load( | 
|  | "//rules:rv.bzl", | 
|  | "rv_rule", | 
|  | _OPENTITAN_CPU = "OPENTITAN_CPU", | 
|  | _OPENTITAN_PLATFORM = "OPENTITAN_PLATFORM", | 
|  | _opentitan_transition = "opentitan_transition", | 
|  | ) | 
|  |  | 
|  | """Rules to build OpenTitan for the RiscV target""" | 
|  |  | 
|  | # Re-exports of names from transition.bzl; many files in the repo use opentitan.bzl | 
|  | # to get to them. | 
|  | OPENTITAN_CPU = _OPENTITAN_CPU | 
|  | OPENTITAN_PLATFORM = _OPENTITAN_PLATFORM | 
|  | opentitan_transition = _opentitan_transition | 
|  |  | 
|  | _targets_compatible_with = { | 
|  | OPENTITAN_PLATFORM: [OPENTITAN_CPU], | 
|  | } | 
|  |  | 
|  | # This constant holds a dictionary of per-device dependencies which are used to | 
|  | # generate slightly different binaries for each hardware target, including two | 
|  | # simulation platforms (DV and Verilator), and two FPGA platforms (NexysVideo | 
|  | # and CW310). | 
|  | PER_DEVICE_DEPS = { | 
|  | "sim_verilator": ["//sw/device/lib/arch:sim_verilator"], | 
|  | "sim_dv": ["//sw/device/lib/arch:sim_dv"], | 
|  | "fpga_cw310": ["//sw/device/lib/arch:fpga_cw310"], | 
|  | } | 
|  |  | 
|  | def _obj_transform_impl(ctx): | 
|  | cc_toolchain = find_cc_toolchain(ctx).cc | 
|  | outputs = [] | 
|  | for src in ctx.files.srcs: | 
|  | binary = ctx.actions.declare_file("{}.{}".format(src.basename, ctx.attr.suffix)) | 
|  | outputs.append(binary) | 
|  | ctx.actions.run( | 
|  | outputs = [binary], | 
|  | inputs = [src] + cc_toolchain.all_files.to_list(), | 
|  | arguments = [ | 
|  | "--output-target", | 
|  | ctx.attr.format, | 
|  | src.path, | 
|  | binary.path, | 
|  | ], | 
|  | executable = cc_toolchain.objcopy_executable, | 
|  | ) | 
|  | return [DefaultInfo(files = depset(outputs), data_runfiles = ctx.runfiles(files = outputs))] | 
|  |  | 
|  | obj_transform = rv_rule( | 
|  | implementation = _obj_transform_impl, | 
|  | attrs = { | 
|  | "srcs": attr.label_list(allow_files = True), | 
|  | "suffix": attr.string(default = "bin"), | 
|  | "format": attr.string(default = "binary"), | 
|  | "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")), | 
|  | }, | 
|  | toolchains = ["@rules_cc//cc:toolchain_type"], | 
|  | ) | 
|  |  | 
|  | def _sign_bin_impl(ctx): | 
|  | outputs = [] | 
|  | signed_image = ctx.actions.declare_file( | 
|  | "{0}.{1}.signed.bin".format( | 
|  | # Remove ".bin" from file basename. | 
|  | ctx.file.bin.basename.replace("." + ctx.file.bin.extension, ""), | 
|  | ctx.attr.key_name, | 
|  | ), | 
|  | ) | 
|  | outputs.append(signed_image) | 
|  | ctx.actions.run( | 
|  | outputs = [signed_image], | 
|  | inputs = [ | 
|  | ctx.file.bin, | 
|  | ctx.file.elf, | 
|  | ctx.file.key, | 
|  | ctx.file._tool, | 
|  | ], | 
|  | arguments = [ | 
|  | "rom_ext", | 
|  | ctx.file.bin.path, | 
|  | ctx.file.key.path, | 
|  | ctx.file.elf.path, | 
|  | signed_image.path, | 
|  | ], | 
|  | executable = ctx.file._tool.path, | 
|  | ) | 
|  | return [DefaultInfo( | 
|  | files = depset(outputs), | 
|  | data_runfiles = ctx.runfiles(files = outputs), | 
|  | )] | 
|  |  | 
|  | sign_bin = rv_rule( | 
|  | implementation = _sign_bin_impl, | 
|  | attrs = { | 
|  | "bin": attr.label(allow_single_file = True), | 
|  | "elf": attr.label(allow_single_file = True), | 
|  | "key": attr.label( | 
|  | default = "//sw/device/silicon_creator/mask_rom/keys:test_private_key_0", | 
|  | allow_single_file = True, | 
|  | ), | 
|  | "key_name": attr.string(), | 
|  | # TODO(lowRISC/opentitan:#11199): explore other options to side-step the | 
|  | # need for this transition, in order to build the ROM_EXT signer tool. | 
|  | "platform": attr.string(default = "@local_config_platform//:host"), | 
|  | "_tool": attr.label( | 
|  | default = "//sw/host/rom_ext_image_tools/signer:rom_ext_signer", | 
|  | allow_single_file = True, | 
|  | ), | 
|  | }, | 
|  | ) | 
|  |  | 
|  | def _elf_to_disassembly_impl(ctx): | 
|  | cc_toolchain = find_cc_toolchain(ctx).cc | 
|  | outputs = [] | 
|  | for src in ctx.files.srcs: | 
|  | disassembly = ctx.actions.declare_file("{}.elf.s".format(src.basename)) | 
|  | outputs.append(disassembly) | 
|  | ctx.actions.run_shell( | 
|  | tools = [ctx.file._cleanup_script], | 
|  | outputs = [disassembly], | 
|  | inputs = [src] + cc_toolchain.all_files.to_list(), | 
|  | arguments = [ | 
|  | cc_toolchain.objdump_executable, | 
|  | src.path, | 
|  | ctx.file._cleanup_script.path, | 
|  | disassembly.path, | 
|  | ], | 
|  | command = "$1 --disassemble --headers --line-numbers --disassemble-zeroes --source $2 | $3 > $4", | 
|  | ) | 
|  | return [DefaultInfo(files = depset(outputs), data_runfiles = ctx.runfiles(files = outputs))] | 
|  |  | 
|  | elf_to_disassembly = rv_rule( | 
|  | implementation = _elf_to_disassembly_impl, | 
|  | attrs = { | 
|  | "srcs": attr.label_list(allow_files = True), | 
|  | "platform": attr.string(default = OPENTITAN_PLATFORM), | 
|  | "_cleanup_script": attr.label( | 
|  | allow_single_file = True, | 
|  | default = Label("//rules/scripts:expand_tabs.sh"), | 
|  | ), | 
|  | "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")), | 
|  | }, | 
|  | toolchains = ["@rules_cc//cc:toolchain_type"], | 
|  | incompatible_use_toolchain_transition = True, | 
|  | ) | 
|  |  | 
|  | def _elf_to_scrambled_rom_impl(ctx): | 
|  | outputs = [] | 
|  | for src in ctx.files.srcs: | 
|  | if src.extension != "elf": | 
|  | fail("only ROM images in the ELF format may be converted to the VMEM format and scrambled.") | 
|  | scrambled = ctx.actions.declare_file( | 
|  | "{}.scr.39.vmem".format( | 
|  | # Remove ".elf" from file basename. | 
|  | src.basename.replace("." + src.extension, ""), | 
|  | ), | 
|  | ) | 
|  | outputs.append(scrambled) | 
|  | ctx.actions.run( | 
|  | outputs = [scrambled], | 
|  | inputs = [ | 
|  | src, | 
|  | ctx.executable._scramble_tool, | 
|  | ctx.file._config, | 
|  | ], | 
|  | arguments = [ | 
|  | ctx.file._config.path, | 
|  | src.path, | 
|  | scrambled.path, | 
|  | ], | 
|  | executable = ctx.executable._scramble_tool, | 
|  | ) | 
|  | return [DefaultInfo( | 
|  | files = depset(outputs), | 
|  | data_runfiles = ctx.runfiles(files = outputs), | 
|  | )] | 
|  |  | 
|  | elf_to_scrambled_rom_vmem = rv_rule( | 
|  | implementation = _elf_to_scrambled_rom_impl, | 
|  | attrs = { | 
|  | "srcs": attr.label_list(allow_files = True), | 
|  | "_scramble_tool": attr.label( | 
|  | default = "//hw/ip/rom_ctrl/util:scramble_image", | 
|  | executable = True, | 
|  | cfg = "exec", | 
|  | ), | 
|  | "_config": attr.label( | 
|  | default = "//hw/top_earlgrey/data:autogen/top_earlgrey.gen.hjson", | 
|  | allow_single_file = True, | 
|  | ), | 
|  | }, | 
|  | ) | 
|  |  | 
|  | def _bin_to_flash_vmem_impl(ctx): | 
|  | outputs = [] | 
|  | vmem = ctx.actions.declare_file("{}.{}.vmem".format( | 
|  | # Remove ".bin" from file basename. | 
|  | ctx.file.bin.basename.replace("." + ctx.file.bin.extension, ""), | 
|  | ctx.attr.word_size, | 
|  | )) | 
|  | outputs.append(vmem) | 
|  | ctx.actions.run( | 
|  | outputs = [vmem], | 
|  | inputs = [ | 
|  | ctx.file.bin, | 
|  | ], | 
|  | arguments = [ | 
|  | ctx.file.bin.path, | 
|  | "--binary", | 
|  | # Reverse the endianness of every word. | 
|  | "--offset", | 
|  | "0x0", | 
|  | "--byte-swap", | 
|  | str(ctx.attr.word_size // 8), | 
|  | # Pad to word alignment. | 
|  | "--fill", | 
|  | "0xff", | 
|  | "-within", | 
|  | ctx.file.bin.path, | 
|  | "-binary", | 
|  | "-range-pad", | 
|  | str(ctx.attr.word_size // 8), | 
|  | # Output a VMEM file with specified word size | 
|  | "--output", | 
|  | vmem.path, | 
|  | "--vmem", | 
|  | str(ctx.attr.word_size), | 
|  | ], | 
|  | # This this executable is expected to be installed (as required by the | 
|  | # srecord package in apt-requirements.txt). | 
|  | executable = "srec_cat", | 
|  | ) | 
|  | return [DefaultInfo( | 
|  | files = depset(outputs), | 
|  | data_runfiles = ctx.runfiles(files = outputs), | 
|  | )] | 
|  |  | 
|  | bin_to_flash_vmem = rv_rule( | 
|  | implementation = _bin_to_flash_vmem_impl, | 
|  | attrs = { | 
|  | "bin": attr.label(allow_single_file = True), | 
|  | "word_size": attr.int( | 
|  | default = 64, | 
|  | doc = "Word size of VMEM file.", | 
|  | mandatory = True, | 
|  | values = [32, 64], | 
|  | ), | 
|  | }, | 
|  | ) | 
|  |  | 
|  | def _scramble_flash_vmem_impl(ctx): | 
|  | outputs = [] | 
|  | scrambled_vmem = ctx.actions.declare_file("{}.scr.vmem".format( | 
|  | # Remove ".vmem" from file basename. | 
|  | ctx.file.vmem.basename.replace("." + ctx.file.vmem.extension, ""), | 
|  | )) | 
|  | outputs.append(scrambled_vmem) | 
|  | ctx.actions.run( | 
|  | outputs = [scrambled_vmem], | 
|  | inputs = [ | 
|  | ctx.file.vmem, | 
|  | ctx.executable._tool, | 
|  | ], | 
|  | arguments = [ | 
|  | ctx.file.vmem.path, | 
|  | scrambled_vmem.path, | 
|  | ], | 
|  | executable = ctx.executable._tool, | 
|  | ) | 
|  | return [DefaultInfo( | 
|  | files = depset(outputs), | 
|  | data_runfiles = ctx.runfiles(files = outputs), | 
|  | )] | 
|  |  | 
|  | scramble_flash_vmem = rv_rule( | 
|  | implementation = _scramble_flash_vmem_impl, | 
|  | attrs = { | 
|  | "vmem": attr.label(allow_single_file = True), | 
|  | "_tool": attr.label( | 
|  | default = "//util/design:gen-flash-img", | 
|  | executable = True, | 
|  | cfg = "exec", | 
|  | ), | 
|  | }, | 
|  | ) | 
|  |  | 
|  | def _bin_to_spiflash_frames_impl(ctx): | 
|  | outputs = [] | 
|  | frames_bin = ctx.actions.declare_file("{}.frames.bin".format( | 
|  | # Remove ".bin" from file basename. | 
|  | ctx.file.bin.basename.replace("." + ctx.file.bin.extension, ""), | 
|  | )) | 
|  | outputs.append(frames_bin) | 
|  | ctx.actions.run( | 
|  | outputs = [frames_bin], | 
|  | inputs = [ | 
|  | ctx.file.bin, | 
|  | ctx.file._tool, | 
|  | ], | 
|  | arguments = [ | 
|  | "--input", | 
|  | ctx.file.bin.path, | 
|  | "--dump-frames", | 
|  | frames_bin.path, | 
|  | ], | 
|  | executable = ctx.file._tool.path, | 
|  | ) | 
|  | return [DefaultInfo( | 
|  | files = depset(outputs), | 
|  | data_runfiles = ctx.runfiles(files = outputs), | 
|  | )] | 
|  |  | 
|  | bin_to_spiflash_frames = rule( | 
|  | implementation = _bin_to_spiflash_frames_impl, | 
|  | cfg = opentitan_transition, | 
|  | attrs = { | 
|  | "bin": attr.label(allow_single_file = True), | 
|  | # TODO(lowRISC/opentitan:#11199): explore other options to side-step the | 
|  | # need for this transition, in order to build the spiflash tool. | 
|  | "platform": attr.string(default = "@local_config_platform//:host"), | 
|  | "_tool": attr.label( | 
|  | default = "//sw/host/spiflash", | 
|  | allow_single_file = True, | 
|  | ), | 
|  | "_allowlist_function_transition": attr.label( | 
|  | default = "@bazel_tools//tools/allowlists/function_transition_allowlist", | 
|  | ), | 
|  | }, | 
|  | ) | 
|  |  | 
|  | def _gen_sim_dv_logs_db_impl(ctx): | 
|  | outputs = [] | 
|  | for src in ctx.files.srcs: | 
|  | if src.extension != "elf": | 
|  | fail("can only generate DV logs database files from ELF files.") | 
|  | logs_db = ctx.actions.declare_file("{}.logs.txt".format( | 
|  | src.basename.replace("." + src.extension, ""), | 
|  | )) | 
|  | rodata = ctx.actions.declare_file("{}.rodata.txt".format( | 
|  | src.basename.replace("." + src.extension, ""), | 
|  | )) | 
|  | outputs.append(logs_db) | 
|  | outputs.append(rodata) | 
|  |  | 
|  | ctx.actions.run( | 
|  | outputs = outputs, | 
|  | inputs = [src], | 
|  | arguments = [ | 
|  | "--elf-file", | 
|  | src.path, | 
|  | "--rodata-sections", | 
|  | ".rodata", | 
|  | "--logs-fields-section", | 
|  | ".logs.fields", | 
|  | "--name", | 
|  | src.basename.replace("." + src.extension, ""), | 
|  | "--outdir", | 
|  | logs_db.dirname, | 
|  | ], | 
|  | executable = ctx.executable._tool, | 
|  | ) | 
|  | return [DefaultInfo( | 
|  | files = depset(outputs), | 
|  | data_runfiles = ctx.runfiles(files = outputs), | 
|  | )] | 
|  |  | 
|  | gen_sim_dv_logs_db = rule( | 
|  | implementation = _gen_sim_dv_logs_db_impl, | 
|  | cfg = opentitan_transition, | 
|  | attrs = { | 
|  | "srcs": attr.label_list(allow_files = True), | 
|  | "platform": attr.string(default = OPENTITAN_PLATFORM), | 
|  | "_tool": attr.label( | 
|  | default = "//util/device_sw_utils:extract_sw_logs_db", | 
|  | cfg = "exec", | 
|  | executable = True, | 
|  | ), | 
|  | "_allowlist_function_transition": attr.label( | 
|  | default = "@bazel_tools//tools/allowlists/function_transition_allowlist", | 
|  | ), | 
|  | }, | 
|  | ) | 
|  |  | 
|  | def opentitan_binary( | 
|  | name, | 
|  | platform = OPENTITAN_PLATFORM, | 
|  | output_bin = True, | 
|  | output_disassembly = True, | 
|  | extract_sw_logs_db = False, | 
|  | **kwargs): | 
|  | """A helper macro for generating OpenTitan binary artifacts. | 
|  |  | 
|  | This macro is mostly a wrapper around cc_binary, but creates artifacts | 
|  | compatible with OpenTitan binaries. The actual artifacts created are an ELF | 
|  | file, a BIN file, the disassembly, and a log message database (text file) | 
|  | for the DV simulation testbench. Each of these output targets performs a | 
|  | bazel transition to the RV32I toolchain to build the target under the | 
|  | correct compiler. | 
|  | Args: | 
|  | @param name: The name of this rule. | 
|  | @param platform: The target platform for the artifacts. | 
|  | @param output_bin: Whether to emit a BIN file. | 
|  | @param output_disassembly: Whether to emit a disassembly file. | 
|  | @param extract_sw_logs_db: Whether to emit a log database for DV testbench. | 
|  | @param **kwargs: Arguments to forward to `cc_binary`. | 
|  | Emits rules: | 
|  | cc_binary             named: <name> | 
|  | optionally: | 
|  | obj_transform       named: <name>_bin | 
|  | elf_to_dissassembly named: <name>_dis | 
|  | gen_sim_dv_logs_db  named: <name>_sim_dv_logs | 
|  | filegroup             named: <name> | 
|  | with all the generated rules | 
|  | """ | 
|  |  | 
|  | copts = kwargs.pop("copts", []) + [ | 
|  | "-nostdlib", | 
|  | "-ffreestanding", | 
|  | ] | 
|  | linkopts = kwargs.pop("linkopts", []) + [ | 
|  | "-nostartfiles", | 
|  | "-nostdlib", | 
|  | ] | 
|  | deps = kwargs.pop("deps", []) | 
|  | targets = [] | 
|  |  | 
|  | # Generate ELF | 
|  | native.cc_binary( | 
|  | name = name, | 
|  | deps = deps, | 
|  | target_compatible_with = _targets_compatible_with[platform], | 
|  | copts = copts, | 
|  | linkopts = linkopts, | 
|  | **kwargs | 
|  | ) | 
|  |  | 
|  | preproc_name = "{}_{}".format(name, "preproc") | 
|  | targets.append(preproc_name) | 
|  | rv_preprocess( | 
|  | name = preproc_name, | 
|  | target = name, | 
|  | ) | 
|  |  | 
|  | asm_name = "{}_{}".format(name, "asm") | 
|  | targets.append(asm_name) | 
|  | rv_asm( | 
|  | name = asm_name, | 
|  | target = name, | 
|  | ) | 
|  |  | 
|  | ll_name = "{}_{}".format(name, "ll") | 
|  | targets.append(ll_name) | 
|  | rv_llvm_ir( | 
|  | name = ll_name, | 
|  | target = name, | 
|  | ) | 
|  |  | 
|  | map_name = "{}_{}".format(name, "map") | 
|  | targets.append(map_name) | 
|  | rv_relink_with_linkmap( | 
|  | name = map_name, | 
|  | target = name, | 
|  | ) | 
|  |  | 
|  | elf_name = "{}_{}".format(name, "elf") | 
|  | targets.append(":" + elf_name) | 
|  | obj_transform( | 
|  | name = elf_name, | 
|  | srcs = [name], | 
|  | format = "elf32-little", | 
|  | suffix = "elf", | 
|  | platform = platform, | 
|  | ) | 
|  |  | 
|  | # Generate Binary | 
|  | if output_bin: | 
|  | bin_name = "{}_{}".format(name, "bin") | 
|  | targets.append(":" + bin_name) | 
|  | obj_transform( | 
|  | name = bin_name, | 
|  | srcs = [name], | 
|  | platform = platform, | 
|  | ) | 
|  |  | 
|  | # Generate Disassembly | 
|  | if output_disassembly: | 
|  | dis_name = "{}_{}".format(name, "dis") | 
|  | targets.append(":" + dis_name) | 
|  | elf_to_disassembly( | 
|  | name = dis_name, | 
|  | srcs = [name], | 
|  | platform = platform, | 
|  | ) | 
|  |  | 
|  | # Generate log message database for DV sim testbench | 
|  | if extract_sw_logs_db: | 
|  | logs_db_name = "{}_{}".format(name, "logs_db") | 
|  | targets.append(":" + logs_db_name) | 
|  | gen_sim_dv_logs_db( | 
|  | name = logs_db_name, | 
|  | srcs = [elf_name], | 
|  | platform = platform, | 
|  | ) | 
|  |  | 
|  | native.filegroup( | 
|  | name = name + "_base_bins", | 
|  | srcs = targets, | 
|  | ) | 
|  |  | 
|  | return targets | 
|  |  | 
|  | def opentitan_rom_binary( | 
|  | name, | 
|  | platform = OPENTITAN_PLATFORM, | 
|  | per_device_deps = PER_DEVICE_DEPS, | 
|  | extract_sw_logs_db = True, | 
|  | **kwargs): | 
|  | """A helper macro for generating OpenTitan binary artifacts for ROM. | 
|  |  | 
|  | This macro is mostly a wrapper around a opentitan_binary macro, which itself | 
|  | is a wrapper around cc_binary, but also creates artifacts for each of the | 
|  | keys in `per_device_deps`. The actual artifacts created are an ELF file, a | 
|  | BIN file, the disassembly, the sim_dv logs database, and the scrambled (ROM) | 
|  | VMEM file. Each of these output targets performs a bazel transition to the | 
|  | RV32I toolchain to build the target under the correct compiler. | 
|  | Args: | 
|  | @param name: The name of this rule. | 
|  | @param platform: The target platform for the artifacts. | 
|  | @param per_device_deps: The deps for each of the hardware target. | 
|  | @param extract_sw_logs_db: Whether to extract SW logs database for DV sim. | 
|  | @param **kwargs: Arguments to forward to `opentitan_binary`. | 
|  | Emits rules: | 
|  | For each device in per_device_deps entry: | 
|  | cc_binary                 named: <name>_<device> | 
|  | obj_transform             named: <name>_<device>_elf | 
|  | obj_transform             named: <name>_<device>_bin | 
|  | elf_to_dissassembly       named: <name>_<device>_dis | 
|  | elf_to_scrambled_rom_vmem named: <name>_<device>_scr_vmem | 
|  | For the sim_dv device: | 
|  | gen_sim_dv_logs_db        named: <name>_sim_dv_logs | 
|  | filegroup named: <name> | 
|  | with all the generated rules | 
|  | """ | 
|  |  | 
|  | deps = kwargs.pop("deps", []) | 
|  | targets = [] | 
|  | for (device, dev_deps) in per_device_deps.items(): | 
|  | devname = "{}_{}".format(name, device) | 
|  |  | 
|  | # Generate ELF, Binary, Disassembly, and (maybe) sim_dv logs database | 
|  | targets.extend(opentitan_binary( | 
|  | name = devname, | 
|  | deps = deps + dev_deps, | 
|  | extract_sw_logs_db = extract_sw_logs_db and device == "sim_dv", | 
|  | **kwargs | 
|  | )) | 
|  | elf_name = "{}_{}".format(devname, "elf") | 
|  |  | 
|  | # Generate Scrambled ROM VMEM | 
|  | scr_vmem_name = "{}_scr_vmem".format(devname) | 
|  | targets.append(":" + scr_vmem_name) | 
|  | elf_to_scrambled_rom_vmem( | 
|  | name = scr_vmem_name, | 
|  | srcs = [elf_name], | 
|  | platform = platform, | 
|  | ) | 
|  |  | 
|  | native.filegroup( | 
|  | name = name, | 
|  | srcs = targets, | 
|  | ) | 
|  |  | 
|  | def opentitan_flash_binary( | 
|  | name, | 
|  | platform = OPENTITAN_PLATFORM, | 
|  | signing_keys = { | 
|  | "test_key_0": "//sw/device/silicon_creator/mask_rom/keys:test_private_key_0", | 
|  | }, | 
|  | per_device_deps = PER_DEVICE_DEPS, | 
|  | extract_sw_logs_db = True, | 
|  | output_signed = False, | 
|  | **kwargs): | 
|  | """A helper macro for generating OpenTitan binary artifacts for flash. | 
|  |  | 
|  | This macro is mostly a wrapper around a opentitan_binary macro, which itself | 
|  | is a wrapper around cc_binary, but also creates artifacts for each of the | 
|  | keys in `per_device_deps`, and if signing is enabled, each of the keys in | 
|  | `signing_keys`. The actual artifacts created are an ELF file, a (signed and) | 
|  | unsigned BIN file, the disassembly, the sim_dv logs database, a (signed and) | 
|  | unsigned flash VMEM file, and a (signed and) unsigned scrambled flash VMEM | 
|  | file. Some of these output targets perform a bazel transition to the RV32I | 
|  | toolchain to build the target under the correct compiler. | 
|  | Args: | 
|  | @param name: The name of this rule. | 
|  | @param platform: The target platform for the artifacts. | 
|  | @param signing_keys: The signing keys for to sign each BIN file with. | 
|  | @param per_device_deps: The deps for each of the hardware target. | 
|  | @param extract_sw_logs_db: Whether to extract SW logs database for DV sim. | 
|  | @param output_signed: Whether or not to emit signed binary/VMEM files. | 
|  | @param **kwargs: Arguments to forward to `opentitan_binary`. | 
|  | Emits rules: | 
|  | For each device in per_device_deps entry: | 
|  | cc_binary              named: <name>_<device> | 
|  | obj_transform          named: <name>_<device>_elf | 
|  | obj_transform          named: <name>_<device>_bin | 
|  | elf_to_dissassembly    named: <name>_<device>_dis | 
|  | bin_to_flash_vmem      named: <name>_<device>_flash_vmem | 
|  | scrambled_flash_vmem   named: <name>_<device>_scr_flash_vmem | 
|  | optionally: | 
|  | sign_bin             named: <name>_<device>_bin_signed_<key_name> | 
|  | bin_to_flash_vmem    named: <name>_<device>_flash_vmem_signed_<key_name> | 
|  | scrambled_flash_vmem named: <name>_<device>_scr_flash_vmem_signed_<key_name> | 
|  | For the sim_dv device: | 
|  | gen_sim_dv_logs_db     named: <name>_sim_dv_logs | 
|  | filegroup named: <name> | 
|  | with all the generated rules | 
|  | """ | 
|  |  | 
|  | deps = kwargs.pop("deps", []) | 
|  | targets = [] | 
|  | for (device, dev_deps) in per_device_deps.items(): | 
|  | devname = "{}_{}".format(name, device) | 
|  |  | 
|  | # Generate ELF, Binary, Disassembly, and (maybe) sim_dv logs database | 
|  | targets.extend(opentitan_binary( | 
|  | name = devname, | 
|  | deps = deps + dev_deps, | 
|  | extract_sw_logs_db = extract_sw_logs_db and device == "sim_dv", | 
|  | **kwargs | 
|  | )) | 
|  | elf_name = "{}_{}".format(devname, "elf") | 
|  | bin_name = "{}_{}".format(devname, "bin") | 
|  |  | 
|  | # Generate SPI flash frames binary for bootstrap in DV sim. | 
|  | if device == "sim_dv": | 
|  | frames_bin_name = "{}_frames_bin".format(devname) | 
|  | targets.append(":" + frames_bin_name) | 
|  | bin_to_spiflash_frames( | 
|  | name = frames_bin_name, | 
|  | bin = bin_name, | 
|  | ) | 
|  | frames_vmem_name = "{}_frames_vmem".format(devname) | 
|  | targets.append(":" + frames_vmem_name) | 
|  | bin_to_flash_vmem( | 
|  | name = frames_vmem_name, | 
|  | bin = frames_bin_name, | 
|  | platform = platform, | 
|  | word_size = 32,  # Bootstrap VMEM image uses 32-bit words | 
|  | ) | 
|  |  | 
|  | # Sign BIN (if required) and generate scrambled VMEM images. | 
|  | if output_signed: | 
|  | for (key_name, key) in signing_keys.items(): | 
|  | # Sign the Binary. | 
|  | signed_bin_name = "{}_bin_signed_{}".format(devname, key_name) | 
|  | targets.append(":" + signed_bin_name) | 
|  | sign_bin( | 
|  | name = signed_bin_name, | 
|  | bin = bin_name, | 
|  | elf = elf_name, | 
|  | key = key, | 
|  | key_name = key_name, | 
|  | ) | 
|  |  | 
|  | # Generate a VMEM64 from the signed binary. | 
|  | signed_vmem_name = "{}_vmem64_signed_{}".format( | 
|  | devname, | 
|  | key_name, | 
|  | ) | 
|  | targets.append(":" + signed_vmem_name) | 
|  | bin_to_flash_vmem( | 
|  | name = signed_vmem_name, | 
|  | bin = signed_bin_name, | 
|  | platform = platform, | 
|  | word_size = 64,  # Backdoor-load VMEM image uses 64-bit words | 
|  | ) | 
|  |  | 
|  | # Scramble signed VMEM64. | 
|  | scr_signed_vmem_name = "{}_scr_vmem64_signed_{}".format( | 
|  | devname, | 
|  | key_name, | 
|  | ) | 
|  | targets.append(":" + scr_signed_vmem_name) | 
|  | scramble_flash_vmem( | 
|  | name = scr_signed_vmem_name, | 
|  | vmem = signed_vmem_name, | 
|  | platform = platform, | 
|  | ) | 
|  | else: | 
|  | # Generate a VMEM64 from the binary. | 
|  | vmem_name = "{}_vmem64".format(devname) | 
|  | targets.append(":" + vmem_name) | 
|  | bin_to_flash_vmem( | 
|  | name = vmem_name, | 
|  | bin = bin_name, | 
|  | platform = platform, | 
|  | word_size = 64,  # Backdoor-load VMEM image uses 64-bit words | 
|  | ) | 
|  |  | 
|  | # Scramble VMEM64. | 
|  | scr_vmem_name = "{}_scr_vmem64".format(devname) | 
|  | targets.append(":" + scr_vmem_name) | 
|  | scramble_flash_vmem( | 
|  | name = scr_vmem_name, | 
|  | vmem = vmem_name, | 
|  | platform = platform, | 
|  | ) | 
|  |  | 
|  | native.filegroup( | 
|  | name = name, | 
|  | srcs = targets, | 
|  | ) |