From 69f3aaad6beab06525d3f80bf33ebad8439c03e1 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Wed, 8 Jan 2025 12:18:01 +0100 Subject: [PATCH] [racl] Static ROT_PRIVATE protection of racl_ctrl Signed-off-by: Robert Schilling --- .../racl_ctrl/data/racl_ctrl.hjson.tpl | 2 +- .../racl_ctrl/rtl/racl_ctrl.sv.tpl | 41 +++++++++++-------- hw/top_darjeeling/rtl/autogen/top_racl_pkg.sv | 6 +++ hw/top_darjeeling/templates/toplevel.sv.tpl | 3 ++ hw/top_earlgrey/rtl/autogen/top_racl_pkg.sv | 6 +++ hw/top_earlgrey/templates/toplevel.sv.tpl | 3 ++ util/raclgen/lib.py | 15 +++++++ util/reggen/bus_interfaces.py | 17 ++++++-- util/reggen/reg_top.sv.tpl | 20 +++++++-- .../topgen/templates/toplevel_racl_pkg.sv.tpl | 6 +++ 10 files changed, 96 insertions(+), 23 deletions(-) diff --git a/hw/ip_templates/racl_ctrl/data/racl_ctrl.hjson.tpl b/hw/ip_templates/racl_ctrl/data/racl_ctrl.hjson.tpl index 4d2c0ac50ab8d..6a4e40dc22627 100644 --- a/hw/ip_templates/racl_ctrl/data/racl_ctrl.hjson.tpl +++ b/hw/ip_templates/racl_ctrl/data/racl_ctrl.hjson.tpl @@ -30,7 +30,7 @@ {clock: "clk_i", reset: "rst_ni"}, ] bus_interfaces: [ - { protocol: "tlul", direction: "device" } + { protocol: "tlul", direction: "device", static_racl_support: true } ], alert_list: [ % if enable_shadow_reg: diff --git a/hw/ip_templates/racl_ctrl/rtl/racl_ctrl.sv.tpl b/hw/ip_templates/racl_ctrl/rtl/racl_ctrl.sv.tpl index b6f8486193a83..994a0a2cd2b17 100644 --- a/hw/ip_templates/racl_ctrl/rtl/racl_ctrl.sv.tpl +++ b/hw/ip_templates/racl_ctrl/rtl/racl_ctrl.sv.tpl @@ -4,7 +4,8 @@ module ${module_instance_name} import ${module_instance_name}_reg_pkg::*; #( parameter logic [NumAlerts-1:0] AlertAsyncOn = {NumAlerts{1'b1}}, - parameter int unsigned NumSubscribingIps = 1 + parameter int unsigned NumSubscribingIps = 1, + parameter bit RaclErrorRsp = 1'b1 ) ( input logic clk_i, input logic rst_ni, @@ -38,21 +39,26 @@ module ${module_instance_name} import ${module_instance_name}_reg_pkg::*; #( % if enable_shadow_reg: // SEC_CM: RACL_POLICY.CONFIG.SHADOW % endif - ${module_instance_name}_reg_top u_racl_ctrl_reg ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), + ${module_instance_name}_reg_top u_racl_ctrl_reg #( + .EnableRacl ( 1'b1 ), + .RaclErrorRsp ( RaclErrorRsp ) + u_racl_ctrl_reg ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), % if enable_shadow_reg: - .rst_shadowed_ni ( rst_shadowed_ni ), + .rst_shadowed_ni ( rst_shadowed_ni ), % endif - .tl_i ( tl_i ), - .tl_o ( tl_o ), - .reg2hw ( reg2hw ), - .hw2reg ( hw2reg ), + .tl_i ( tl_i ), + .tl_o ( tl_o ), + .reg2hw ( reg2hw ), + .hw2reg ( hw2reg ), % if enable_shadow_reg: - .shadowed_storage_err_o ( shadowed_storage_err ), - .shadowed_update_err_o ( shadowed_update_err ), + .shadowed_storage_err_o ( shadowed_storage_err ), + .shadowed_update_err_o ( shadowed_update_err ), % endif - .intg_err_o ( reg_intg_error ) + .racl_error_o ( racl_ctrl_racl_error ), + .racl_error_log_o ( racl_ctrl_racl_error_log ), + .intg_err_o ( reg_intg_error ) ); ////////////////////////////////////////////////////////////////////////////////////////////////// @@ -130,7 +136,8 @@ module ${module_instance_name} import ${module_instance_name}_reg_pkg::*; #( `ASSERT(OneHotRaclError_A, $onehot0(racl_error_i)) logic racl_error; - assign racl_error = |racl_error_i; + // A combined RACL error from external subscribing IPs in the racl_ctrl internal reg_top + assign racl_error = |racl_error_i | racl_ctrl_racl_error; top_racl_pkg::racl_role_t racl_error_role; top_racl_pkg::ctn_uid_t racl_error_ctn_uid; @@ -139,9 +146,11 @@ module ${module_instance_name} import ${module_instance_name}_reg_pkg::*; #( // Reduce all incoming error vectors to a single role and write/read bit. // Only a single IP can have a RACL error at one time. always_comb begin - racl_error_role = '0; - racl_error_ctn_uid = '0; - racl_error_read_not_write = 1'b0; + // Default to the racl_ctrl reg_top error information. Possible since only + // one error allowed at a time. + racl_error_role = racl_ctrl_racl_error_log.racl_role; + racl_error_ctn_uid = racl_ctrl_racl_error_log.ctn_uid; + racl_error_read_not_write = racl_ctrl_racl_error_log.read_not_write; for (int i = 0; i < NumSubscribingIps; i++) begin racl_error_role |= racl_error_log_i[i].racl_role; racl_error_ctn_uid |= racl_error_log_i[i].ctn_uid; diff --git a/hw/top_darjeeling/rtl/autogen/top_racl_pkg.sv b/hw/top_darjeeling/rtl/autogen/top_racl_pkg.sv index f3f2c30c1b4c5..148e4424bb115 100644 --- a/hw/top_darjeeling/rtl/autogen/top_racl_pkg.sv +++ b/hw/top_darjeeling/rtl/autogen/top_racl_pkg.sv @@ -42,6 +42,12 @@ package top_racl_pkg; // Default policy vector for unconnected RACL IPs parameter racl_policy_vec_t RACL_POLICY_VEC_DEFAULT = '0; + // Default ROT Private read policy value + parameter racl_policy_vec_t RACL_POLICY_ROT_PRIVATE_RD = 16'h0; + + // Default ROT Private write policy value + parameter racl_policy_vec_t RACL_POLICY_ROT_PRIVATE_WR = 16'h0; + // RACL information logged in case of a denial typedef struct packed { racl_role_t racl_role; diff --git a/hw/top_darjeeling/templates/toplevel.sv.tpl b/hw/top_darjeeling/templates/toplevel.sv.tpl index e09f5f8f0da03..da69e2e789202 100644 --- a/hw/top_darjeeling/templates/toplevel.sv.tpl +++ b/hw/top_darjeeling/templates/toplevel.sv.tpl @@ -476,6 +476,9 @@ max_intrwidth = (max(len(x.name) for x in block.interrupts) .RaclPolicySelVec(top_racl_pkg::RACL_POLICY_SEL_${m["name"].upper()}${if_prefix}), % endfor % endif + % if m['type'].startswith('racl_ctrl'): + .RaclErrorRsp(${"1'b1" if top['racl']['error_response'] else "1'b0"}), + % endif % if block.alerts: <% w = len(block.alerts) diff --git a/hw/top_earlgrey/rtl/autogen/top_racl_pkg.sv b/hw/top_earlgrey/rtl/autogen/top_racl_pkg.sv index d768a5c45eae1..517d52b5c1eee 100644 --- a/hw/top_earlgrey/rtl/autogen/top_racl_pkg.sv +++ b/hw/top_earlgrey/rtl/autogen/top_racl_pkg.sv @@ -42,6 +42,12 @@ package top_racl_pkg; // Default policy vector for unconnected RACL IPs parameter racl_policy_vec_t RACL_POLICY_VEC_DEFAULT = '0; + // Default ROT Private read policy value + parameter racl_policy_vec_t RACL_POLICY_ROT_PRIVATE_RD = 16'h0; + + // Default ROT Private write policy value + parameter racl_policy_vec_t RACL_POLICY_ROT_PRIVATE_WR = 16'h0; + // RACL information logged in case of a denial typedef struct packed { racl_role_t racl_role; diff --git a/hw/top_earlgrey/templates/toplevel.sv.tpl b/hw/top_earlgrey/templates/toplevel.sv.tpl index dbaabba17169a..151afe6d2d17e 100644 --- a/hw/top_earlgrey/templates/toplevel.sv.tpl +++ b/hw/top_earlgrey/templates/toplevel.sv.tpl @@ -503,6 +503,9 @@ max_intrwidth = (max(len(x.name) for x in block.interrupts) .RaclPolicySelVec(top_racl_pkg::RACL_POLICY_SEL_${m["name"].upper()}${if_prefix}), % endfor % endif + % if m['type'].startswith('racl_ctrl'): + .RaclErrorRsp(${"1'b1" if top['racl']['error_response'] else "1'b0"}), + % endif % if block.alerts: <% w = len(block.alerts) diff --git a/util/raclgen/lib.py b/util/raclgen/lib.py index 4bc477636298c..ad5aefed59395 100644 --- a/util/raclgen/lib.py +++ b/util/raclgen/lib.py @@ -22,6 +22,8 @@ DEFAULT_RACL_CONFIG = { 'nr_policies': 1, 'policies': {}, + 'rot_private_policy_rd': 0, + 'rot_private_policy_wr': 0 } @@ -45,6 +47,7 @@ def parse_racl_config(config_path: str) -> Dict[str, object]: # 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()) + rot_private_policy = None for racl_group, policies in racl_config['policies'].items(): for policy in policies: def compute_policy_value(permission: str) -> int: @@ -56,6 +59,18 @@ def compute_policy_value(permission: str) -> int: policy['rd_default'] = compute_policy_value('allowed_rd') policy['wr_default'] = compute_policy_value('allowed_wr') + if policy.get('rot_private'): + if rot_private_policy: + raise ValueError('Only one policy can be the ROT_PRIVATE policy') + rot_private_policy = policy + + if not rot_private_policy: + raise ValueError('No ROT_PRIVATE policy defined') + + # Get the default ROT private policy for static RACL protection of the racl_ctrl IP(s) + racl_config['rot_private_policy_rd'] = rot_private_policy['rd_default'] + racl_config['rot_private_policy_wr'] = rot_private_policy['wr_default'] + return racl_config diff --git a/util/reggen/bus_interfaces.py b/util/reggen/bus_interfaces.py index b3dc380b61bd1..ca1f4acadff20 100644 --- a/util/reggen/bus_interfaces.py +++ b/util/reggen/bus_interfaces.py @@ -19,7 +19,8 @@ def __init__(self, named_devices: List[str], device_async: Dict[Optional[str], str], device_hier_paths: Dict[Optional[str], str], - racl_support: Dict[Optional[str], bool]): + racl_support: Dict[Optional[str], bool], + static_racl_support: Dict[Optional[str], bool]): assert has_unnamed_device or named_devices assert len(named_hosts) == len(set(named_hosts)) assert len(named_devices) == len(set(named_devices)) @@ -32,6 +33,7 @@ def __init__(self, self.device_async = device_async self.device_hier_paths = device_hier_paths self.racl_support = racl_support + self.static_racl_support = static_racl_support @staticmethod def from_raw(raw: object, where: str) -> 'BusInterfaces': @@ -44,12 +46,14 @@ def from_raw(raw: object, where: str) -> 'BusInterfaces': device_async = {} device_hier_paths = {} racl_support_map = {} + static_racl_support_map = {} for idx, raw_entry in enumerate(check_list(raw, where)): entry_what = 'entry {} of {}'.format(idx + 1, where) ed = check_keys(raw_entry, entry_what, ['protocol', 'direction'], - ['name', 'async', 'hier_path', 'racl_support']) + ['name', 'async', 'hier_path', + 'racl_support', 'static_racl_support']) protocol = check_str(ed['protocol'], 'protocol field of ' + entry_what) @@ -74,6 +78,8 @@ def from_raw(raw: object, where: str) -> 'BusInterfaces': racl_support = check_optional_bool(ed.get('racl_support'), 'racl_support field of ' + entry_what) + static_racl_support = check_optional_bool(ed.get('static_racl_support'), + 'static_racl_support field of ' + entry_what) if direction == 'host': if name is None: @@ -117,14 +123,19 @@ def from_raw(raw: object, where: str) -> 'BusInterfaces': else: device_hier_paths[name] = 'u_reg' + if racl_support and static_racl_support: + raise ValueError("Device interface cannot support both static and dynamic RACL") + racl_support_map[name] = bool(racl_support) + static_racl_support_map[name] = bool(static_racl_support) if not (has_unnamed_device or named_devices): raise ValueError('No device interface at ' + where) return BusInterfaces(has_unnamed_host, named_hosts, host_async, has_unnamed_device, named_devices, - device_async, device_hier_paths, racl_support_map) + device_async, device_hier_paths, + racl_support_map, static_racl_support_map) def has_host(self) -> bool: return bool(self.has_unnamed_host or self.named_hosts) diff --git a/util/reggen/reg_top.sv.tpl b/util/reggen/reg_top.sv.tpl index 42f8f7fc4b260..5307805eee291 100644 --- a/util/reggen/reg_top.sv.tpl +++ b/util/reggen/reg_top.sv.tpl @@ -33,7 +33,9 @@ reg2hw_t = gen_rtl.get_iface_tx_type(block, if_name, False) hw2reg_t = gen_rtl.get_iface_tx_type(block, if_name, True) - racl_support = block.bus_interfaces.racl_support[if_name] + dynamic_racl_support = block.bus_interfaces.racl_support[if_name] + static_racl_support = block.bus_interfaces.static_racl_support[if_name] + racl_support = dynamic_racl_support or static_racl_support win_array_decl = f' [{num_wins}]' if num_wins > 1 else '' @@ -121,8 +123,10 @@ module ${mod_name}${' (' if not racl_support else ''} % if racl_support: # ( parameter bit EnableRacl = 1'b0, - parameter bit RaclErrorRsp = 1'b1, + parameter bit RaclErrorRsp = 1'b1${"," if dynamic_racl_support else ""} + % if dynamic_racl_support: parameter int unsigned RaclPolicySelVec[${len(rb.flat_regs)}] = '{${len(rb.flat_regs)}{0}} + % endif ) ( % endif input clk_i, @@ -158,7 +162,9 @@ module ${mod_name}${' (' if not racl_support else ''} %endif % if racl_support: // RACL interface +% if dynamic_racl_support: input top_racl_pkg::racl_policy_vec_t racl_policies_i, +% endif output logic racl_error_o, output top_racl_pkg::racl_error_log_t racl_error_log_o, @@ -700,12 +706,20 @@ ${finst_gen(sr, field, finst_name, fsig_name, fidx)} if (EnableRacl) begin : gen_racl_hit for (int unsigned slice_idx = 0; slice_idx < ${len(regs_flat)}; slice_idx++) begin + % if dynamic_racl_support: racl_addr_hit_read[slice_idx] = addr_hit[slice_idx] & (|(racl_policies_i[RaclPolicySelVec[slice_idx]].read_perm & racl_role_vec)); racl_addr_hit_write[slice_idx] = addr_hit[slice_idx] & (|(racl_policies_i[RaclPolicySelVec[slice_idx]].write_perm & racl_role_vec)); + % else: + // Static RACL protection with ROT_PRIVATE policy + racl_addr_hit_read[slice_idx] = + addr_hit[slice_idx] & (|(top_racl_pkg::RACL_POLICY_ROT_PRIVATE_RD & racl_role_vec)); + racl_addr_hit_write[slice_idx] = + addr_hit[slice_idx] & (|(top_racl_pkg::RACL_POLICY_ROT_PRIVATE_WR & racl_role_vec)); + % endif end end else begin : gen_no_racl racl_addr_hit_read = addr_hit; @@ -916,7 +930,7 @@ ${rdata_gen(f, r.name.lower() + "_" + f.name.lower())}\ assign unused_wdata = ^reg_wdata; assign unused_be = ^reg_be; % endif -% if racl_support: +% if dynamic_racl_support: logic unused_policy_sel; assign unused_policy_sel = ^racl_policies_i; % endif diff --git a/util/topgen/templates/toplevel_racl_pkg.sv.tpl b/util/topgen/templates/toplevel_racl_pkg.sv.tpl index 318cab44630e6..103dc8bd35b8b 100644 --- a/util/topgen/templates/toplevel_racl_pkg.sv.tpl +++ b/util/topgen/templates/toplevel_racl_pkg.sv.tpl @@ -34,6 +34,12 @@ package top_racl_pkg; // Default policy vector for unconnected RACL IPs parameter racl_policy_vec_t RACL_POLICY_VEC_DEFAULT = '0; + // Default ROT Private read policy value + parameter racl_policy_vec_t RACL_POLICY_ROT_PRIVATE_RD = 16'h${f"{racl_config['rot_private_policy_rd']:x}"}; + + // Default ROT Private write policy value + parameter racl_policy_vec_t RACL_POLICY_ROT_PRIVATE_WR = 16'h${f"{racl_config['rot_private_policy_wr']:x}"}; + // RACL information logged in case of a denial typedef struct packed { racl_role_t racl_role;