diff --git a/hw/top_darjeeling/rtl/autogen/top_racl_pkg.sv b/hw/top_darjeeling/rtl/autogen/top_racl_pkg.sv new file mode 100644 index 0000000000000..5f1bbf2ad59f8 --- /dev/null +++ b/hw/top_darjeeling/rtl/autogen/top_racl_pkg.sv @@ -0,0 +1,69 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// ------------------- W A R N I N G: A U T O - G E N E R A T E D C O D E !! -------------------// +// PLEASE DO NOT HAND-EDIT THIS FILE. IT HAS BEEN AUTO-GENERATED WITH THE FOLLOWING COMMAND: +// +// util/topgen.py -t hw/top_darjeeling/data/top_darjeeling.hjson \ +// -o hw/top_darjeeling/ \ +// --rnd_cnst_seed \ +// 1017106219537032642877583828875051302543807092889754935647094601236425074047 + + +package top_racl_pkg; + // Number of RACL policies used + parameter int unsigned NrRaclPolicies = 1; + + // Number of RACL bits transferred + parameter int unsigned NrRaclBits = 4; + + // Number of CTN UID bits transferred + parameter int unsigned NrCtnUidBits = 8; + + // RACL role type binary encoded + typedef logic [NrRaclBits-1:0] racl_role_t; + + // CTN UID assigned the bus originator + typedef logic [NrCtnUidBits-1:0] ctn_uid_t; + + // RACL permission: A one-hot encoded role vector + typedef logic [(2**NrRaclBits)-1:0] racl_role_vec_t; + + // RACL policy containing a read and write permission + typedef struct packed { + racl_role_vec_t read_perm; + racl_role_vec_t write_perm; + } racl_policy_t; + + // RACL policy vector for distributing RACL policies from the RACL widget to the subscribing IP + typedef racl_policy_t [NrRaclPolicies-1:0] racl_policy_vec_t; + + // RACL information logged in case of a denial + typedef struct packed { + racl_role_t racl_role; + ctn_uid_t ctn_uid; + // 0: Write access, 1: Read access + logic read_not_write; + } racl_error_log_t; + + // Extract RACL role bits from the TLUL reserved user bits + function automatic racl_role_t tlul_extract_racl_role_bits(logic [tlul_pkg::RsvdWidth-1:0] rsvd); + // Waive unused bits + logic unused_rsvd_bits; + unused_rsvd_bits = ^{rsvd}; + + return racl_role_t'(rsvd[11:8]); + endfunction + + // Extract CTN UID bits from the TLUL reserved user bits + function automatic ctn_uid_t tlul_extract_ctn_uid_bits(logic [tlul_pkg::RsvdWidth-1:0] rsvd); + // Waive unused bits + logic unused_rsvd_bits; + unused_rsvd_bits = ^{rsvd}; + + return ctn_uid_t'(rsvd[7:0]); + endfunction + + +endpackage diff --git a/hw/top_darjeeling/top_darjeeling.core b/hw/top_darjeeling/top_darjeeling.core index 108548bbcb529..164974ce4dce8 100644 --- a/hw/top_darjeeling/top_darjeeling.core +++ b/hw/top_darjeeling/top_darjeeling.core @@ -8,6 +8,7 @@ filesets: files_rtl_generic: depend: # Place the autogen packages first to avoid conflicts + - lowrisc:systems:top_darjeeling_racl_pkg - lowrisc:opentitan:top_darjeeling_alert_handler_reg - lowrisc:opentitan:top_darjeeling_pwrmgr_pkg - lowrisc:ip:uart:0.1 diff --git a/hw/top_darjeeling/top_darjeeling_racl_pkg.core b/hw/top_darjeeling/top_darjeeling_racl_pkg.core new file mode 100644 index 0000000000000..b6ebe966f8f84 --- /dev/null +++ b/hw/top_darjeeling/top_darjeeling_racl_pkg.core @@ -0,0 +1,21 @@ +CAPI=2: +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:systems:top_darjeeling_racl_pkg:0.1" +description: "Autogenerated top_darjeeling_racl_pkg used in RTL and DV." +virtual: + - lowrisc:systems:top_racl_pkg + +filesets: + files_rtl: + depend: + - lowrisc:tlul:headers + files: + - rtl/autogen/top_racl_pkg.sv + file_type: systemVerilogSource + +targets: + default: &default_target + filesets: + - files_rtl diff --git a/hw/top_earlgrey/rtl/autogen/top_racl_pkg.sv b/hw/top_earlgrey/rtl/autogen/top_racl_pkg.sv new file mode 100644 index 0000000000000..da876a03816ac --- /dev/null +++ b/hw/top_earlgrey/rtl/autogen/top_racl_pkg.sv @@ -0,0 +1,69 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// ------------------- W A R N I N G: A U T O - G E N E R A T E D C O D E !! -------------------// +// PLEASE DO NOT HAND-EDIT THIS FILE. IT HAS BEEN AUTO-GENERATED WITH THE FOLLOWING COMMAND: +// +// util/topgen.py -t hw/top_earlgrey/data/top_earlgrey.hjson \ +// -o hw/top_earlgrey/ \ +// --rnd_cnst_seed \ +// 1017106219537032642877583828875051302543807092889754935647094601236425074047 + + +package top_racl_pkg; + // Number of RACL policies used + parameter int unsigned NrRaclPolicies = 1; + + // Number of RACL bits transferred + parameter int unsigned NrRaclBits = 4; + + // Number of CTN UID bits transferred + parameter int unsigned NrCtnUidBits = 8; + + // RACL role type binary encoded + typedef logic [NrRaclBits-1:0] racl_role_t; + + // CTN UID assigned the bus originator + typedef logic [NrCtnUidBits-1:0] ctn_uid_t; + + // RACL permission: A one-hot encoded role vector + typedef logic [(2**NrRaclBits)-1:0] racl_role_vec_t; + + // RACL policy containing a read and write permission + typedef struct packed { + racl_role_vec_t read_perm; + racl_role_vec_t write_perm; + } racl_policy_t; + + // RACL policy vector for distributing RACL policies from the RACL widget to the subscribing IP + typedef racl_policy_t [NrRaclPolicies-1:0] racl_policy_vec_t; + + // RACL information logged in case of a denial + typedef struct packed { + racl_role_t racl_role; + ctn_uid_t ctn_uid; + // 0: Write access, 1: Read access + logic read_not_write; + } racl_error_log_t; + + // Extract RACL role bits from the TLUL reserved user bits + function automatic racl_role_t tlul_extract_racl_role_bits(logic [tlul_pkg::RsvdWidth-1:0] rsvd); + // Waive unused bits + logic unused_rsvd_bits; + unused_rsvd_bits = ^{rsvd}; + + return racl_role_t'(rsvd[11:8]); + endfunction + + // Extract CTN UID bits from the TLUL reserved user bits + function automatic ctn_uid_t tlul_extract_ctn_uid_bits(logic [tlul_pkg::RsvdWidth-1:0] rsvd); + // Waive unused bits + logic unused_rsvd_bits; + unused_rsvd_bits = ^{rsvd}; + + return ctn_uid_t'(rsvd[7:0]); + endfunction + + +endpackage diff --git a/hw/top_earlgrey/top_earlgrey.core b/hw/top_earlgrey/top_earlgrey.core index 49a1a40993ccf..52deeb2601c1d 100644 --- a/hw/top_earlgrey/top_earlgrey.core +++ b/hw/top_earlgrey/top_earlgrey.core @@ -8,6 +8,7 @@ filesets: files_rtl_generic: depend: # Place the autogen packages first to avoid conflicts + - lowrisc:systems:top_earlgrey_racl_pkg - lowrisc:opentitan:top_earlgrey_alert_handler_reg - lowrisc:opentitan:top_earlgrey_pwrmgr_pkg - lowrisc:ip:uart:0.1 diff --git a/hw/top_earlgrey/top_earlgrey_racl_pkg.core b/hw/top_earlgrey/top_earlgrey_racl_pkg.core new file mode 100644 index 0000000000000..1d25e0a0e50ed --- /dev/null +++ b/hw/top_earlgrey/top_earlgrey_racl_pkg.core @@ -0,0 +1,21 @@ +CAPI=2: +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +name: "lowrisc:systems:top_earlgrey_racl_pkg:0.1" +description: "Autogenerated top_earlgrey_racl_pkg used in RTL and DV." +virtual: + - lowrisc:systems:top_racl_pkg + +filesets: + files_rtl: + depend: + - lowrisc:tlul:headers + files: + - rtl/autogen/top_racl_pkg.sv + file_type: systemVerilogSource + +targets: + default: &default_target + filesets: + - files_rtl diff --git a/util/raclgen/__init__.py b/util/raclgen/__init__.py new file mode 100644 index 0000000000000..3e8bb41965a28 --- /dev/null +++ b/util/raclgen/__init__.py @@ -0,0 +1,3 @@ +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 diff --git a/util/raclgen/lib.py b/util/raclgen/lib.py new file mode 100644 index 0000000000000..a42e6471a8f10 --- /dev/null +++ b/util/raclgen/lib.py @@ -0,0 +1,52 @@ +# Copyright lowRISC contributors (OpenTitan project). +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +import hjson +import sys +from reggen.validate import check_keys +from typing import Dict + +# Required fields for the RACL hjson +racl_required = { + 'roles': ['l', 'List, specifying all RACL roles'], + 'policies': ['g', 'Dict, specifying the policies of all RACL groups'] +} + + +# Default configuration to render the RACL package for systems that don't use RACL but need the +# type definitions +DEFAULT_RACL_CONFIG = { + 'nr_policies': 1, + 'policies': {}, +} + + +def parse_racl_config(config_path: str) -> Dict[str, object]: + try: + with open(config_path, 'r') as f_racl_config: + racl_config = hjson.load(f_racl_config) + except OSError: + raise SystemExit(sys.exc_info()[1]) + + # TODO(#25690) Further sanity checks on the parsed RACL config + error = check_keys(racl_config, racl_required, [], [], 'RACL Config') + if error: + raise SystemExit(f"Error occurred while validating {config_path}") + + # Determine the maximum number of policies over all RACL groups for RTL + # RTL needs to create the vectors based on the largest group + racl_config['nr_policies'] = max(len(policies) for policies in racl_config['policies'].values()) + + for racl_group, policies in racl_config['policies'].items(): + for policy in policies: + def compute_policy_value(permission: str) -> int: + permission_value = 0 + for role in policy[permission]: + role_id = racl_config['roles'][role]['role_id'] + permission_value += 2**role_id + return permission_value + + policy['rd_default'] = compute_policy_value('allowed_rd') + policy['wr_default'] = compute_policy_value('allowed_wr') + return racl_config diff --git a/util/topgen.py b/util/topgen.py index b780996dcf974..67722dcb13e10 100755 --- a/util/topgen.py +++ b/util/topgen.py @@ -21,6 +21,7 @@ IpTemplate, TemplateRenderError) from mako import exceptions from mako.template import Template +from raclgen.lib import DEFAULT_RACL_CONFIG, parse_racl_config from reggen import access, gen_rtl, gen_sec_cm_testplan, window from reggen.countermeasure import CounterMeasure from reggen.inter_signal import InterSignal @@ -526,6 +527,15 @@ def generate_ac_range_check(topcfg: Dict[str, object], out_path: Path) -> None: ipgen_render("ac_range_check", topname, params, out_path) +# Generate RACL collateral +def generate_racl(topcfg: Dict[str, object], out_path: Path) -> None: + # Not all tops use RACL + if 'racl_config' not in topcfg: + return + + topcfg['racl'] = parse_racl_config(topcfg['racl_config']) + + def generate_top_only(top_only_dict: Dict[str, bool], out_path: Path, top_name: str, alt_hjson_path: str) -> None: log.info("Generating top only modules") @@ -866,6 +876,9 @@ def _process_top( # Generate ac_range_check generate_ac_range_check(completecfg, out_path) + # Generate RACL collateral + generate_racl(completecfg, out_path) + # Generate top only modules # These modules are not ipgen, but are not in hw/ip generate_top_only(top_only_dict, cfg_path, top_name, args.hjson_path) @@ -1249,6 +1262,12 @@ def render_template(template_path: str, rendered_path: Path, out_path / f"rtl/autogen/{top_name}_rnd_cnst_pkg.sv", gencmd=gencmd) + racl_config = completecfg.get('racl', DEFAULT_RACL_CONFIG) + render_template(TOPGEN_TEMPLATE_PATH / 'toplevel_racl_pkg.sv.tpl', + out_path / 'rtl' / 'autogen' / 'top_racl_pkg.sv', + gencmd=gencmd, + racl_config=racl_config) + # Since SW does not use FuseSoC and instead expects those files always # to be in hw/top_{topname}/sw/autogen, we currently create these files # twice: diff --git a/util/topgen/templates/toplevel_racl_pkg.sv.tpl b/util/topgen/templates/toplevel_racl_pkg.sv.tpl new file mode 100644 index 0000000000000..bc75b4ba6e2a0 --- /dev/null +++ b/util/topgen/templates/toplevel_racl_pkg.sv.tpl @@ -0,0 +1,82 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +${gencmd} + +package top_racl_pkg; + // Number of RACL policies used + parameter int unsigned NrRaclPolicies = ${racl_config['nr_policies']}; + + // Number of RACL bits transferred + parameter int unsigned NrRaclBits = 4; + + // Number of CTN UID bits transferred + parameter int unsigned NrCtnUidBits = 8; + + // RACL role type binary encoded + typedef logic [NrRaclBits-1:0] racl_role_t; + + // CTN UID assigned the bus originator + typedef logic [NrCtnUidBits-1:0] ctn_uid_t; + + // RACL permission: A one-hot encoded role vector + typedef logic [(2**NrRaclBits)-1:0] racl_role_vec_t; + + // RACL policy containing a read and write permission + typedef struct packed { + racl_role_vec_t read_perm; + racl_role_vec_t write_perm; + } racl_policy_t; + + // RACL policy vector for distributing RACL policies from the RACL widget to the subscribing IP + typedef racl_policy_t [NrRaclPolicies-1:0] racl_policy_vec_t; + + // RACL information logged in case of a denial + typedef struct packed { + racl_role_t racl_role; + ctn_uid_t ctn_uid; + // 0: Write access, 1: Read access + logic read_not_write; + } racl_error_log_t; + + // Extract RACL role bits from the TLUL reserved user bits + function automatic racl_role_t tlul_extract_racl_role_bits(logic [tlul_pkg::RsvdWidth-1:0] rsvd); + // Waive unused bits + logic unused_rsvd_bits; + unused_rsvd_bits = ^{rsvd}; + + return racl_role_t'(rsvd[11:8]); + endfunction + + // Extract CTN UID bits from the TLUL reserved user bits + function automatic ctn_uid_t tlul_extract_ctn_uid_bits(logic [tlul_pkg::RsvdWidth-1:0] rsvd); + // Waive unused bits + logic unused_rsvd_bits; + unused_rsvd_bits = ^{rsvd}; + + return ctn_uid_t'(rsvd[7:0]); + endfunction + +% for racl_group, policies in racl_config['policies'].items(): +<% prefix = "" if len(racl_config['policies'].keys()) == 1 else f"{racl_group.upper()}_" %>\ + /** + * Policies for group ${racl_group} + */ + + % for policy in policies: + /* + * Policy ${policy['name']} allowed READ roles: + * ${', '.join(policy['allowed_wr'])} + */ + parameter racl_policy_t RACL_POLICY_${prefix}${policy['name'].upper()}_RD_DEFAULT = 16'h${f"{policy['rd_default']:x}"}; + + /** + * Policy ${policy['name']} allowed WRITE roles: + * ${', '.join(policy['allowed_wr'])} + */ + parameter racl_policy_t RACL_POLICY_${prefix}${policy['name'].upper()}_WR_DEFAULT = 16'h${f"{policy['wr_default']:x}"}; + + % endfor +% endfor + +endpackage diff --git a/util/topgen/validate.py b/util/topgen/validate.py index 0919a78d23d3b..31a588a9a937a 100644 --- a/util/topgen/validate.py +++ b/util/topgen/validate.py @@ -71,6 +71,7 @@ 'num_cores': ['pn', "number of computing units"], 'power': ['g', 'power domains supported by the design'], 'port': ['g', 'assign special attributes to specific ports'], + 'racl_config': ['s', 'Path to a RACL configuration HJSON file'], 'rnd_cnst_seed': ['int', "Seed for random netlist constant computation"], 'unmanaged_resets': ['l', 'List of unmanaged external resets'] }